4 回答

TA貢獻(xiàn)1794條經(jīng)驗(yàn) 獲得超8個(gè)贊
這是不可能的。原因之一是傳遞參數(shù)的機(jī)制因函數(shù)而異,使用interface{}
arg 并不意味著“接受任何東西”。例如,一個(gè)以結(jié)構(gòu)為參數(shù)的函數(shù)將接收該結(jié)構(gòu)的每個(gè)成員,但一個(gè)以包含該結(jié)構(gòu)的 interface{} 的函數(shù)將接收兩個(gè)字,一個(gè)包含結(jié)構(gòu)的類(lèi)型,另一個(gè)包含指向它。
因此,在不使用泛型的情況下,實(shí)現(xiàn)這一點(diǎn)的唯一方法是使用適配器函數(shù)。

TA貢獻(xiàn)2011條經(jīng)驗(yàn) 獲得超2個(gè)贊
使用反射包來(lái)處理具有任意參數(shù)和結(jié)果類(lèi)型的函數(shù)。
func decorate(inner interface{}, args interface{}) interface{} {
fmt.Println("Before inner")
result := reflect.ValueOf(inner).Call([]reflect.Value{reflect.ValueOf(args)})
fmt.Println("After inner")
return result[0].Interface()
}
在操場(chǎng)上運(yùn)行代碼。
與decorate問(wèn)題中的函數(shù)一樣,此答案中的函數(shù)假定一個(gè)參數(shù)和一個(gè)結(jié)果。必須修改該函數(shù)以處理其他函數(shù)類(lèi)型。
OP 應(yīng)考慮問(wèn)題中提出的匿名包裝函數(shù)與此處使用反射包之間的權(quán)衡。通過(guò)反射 API 調(diào)用函數(shù)比通過(guò)匿名包裝器調(diào)用函數(shù)慢。反射 API 也失去了類(lèi)型安全性。匿名包裝函數(shù)增加了冗長(zhǎng)性。

TA貢獻(xiàn)1784條經(jīng)驗(yàn) 獲得超2個(gè)贊
作為記錄,隨著 Go 1.18 和泛型的引入,該decorator功能變得幾乎微不足道。
您可以這樣聲明類(lèi)型約束:
type UnaryFunc[T any] interface {
func(T) T
}
約束本身被參數(shù)化T以允許接受和返回任意類(lèi)型的一元函數(shù)。
然后在decorate函數(shù)中使用類(lèi)型參數(shù)實(shí)例化約束。簽名變?yōu)椋?/p>
decorate[T any, F UnaryFunc[T]](inner F, arg T) T
多虧了類(lèi)型推斷,您可以只將具體參數(shù)傳遞給函數(shù),并且兩者T都是F明確的。
沒(méi)有命名約束的示例替代方案:
// accept and return T
decorate[T any](inner func(T) T, arg T) T
// only return T
decorate[T any](inner func() T) T
// return T and error
decorate[T any](inner func(T) (T, error), arg T) (T, error)
// N-ary function
decorate[T, U any](inner func(T, U) (T, error), argt T, argu U) (T, error)
明顯的限制是接口約束UnaryFunc只指定了只接受和返回一個(gè) arg 類(lèi)型的函數(shù)T。你不能這樣做,因?yàn)榻涌诩s束的類(lèi)型集可能包括支持相同操作的類(lèi)型——并且使用一個(gè) arg 調(diào)用與使用 N 個(gè) args 調(diào)用不兼容。
完整程序:
package main
import (
"fmt"
)
type UnaryFunc[T any] interface {
func(T) T
}
func decorate[T any, F UnaryFunc[T]](inner F, arg T) T {
fmt.Println("before inner")
result := inner(arg)
fmt.Println("after inner")
return result
}
func funcA(arg int) int {
fmt.Println("inside A with:", arg)
return arg
}
func funcB(arg string) string {
fmt.Println("inside B with:", arg)
return arg
}
func main() {
// this works
decorate(funcA, 200)
// this also works
decorate(funcB, "Func B")
}
游樂(lè)場(chǎng):https ://go.dev/play/p/3q01NiiWsve

TA貢獻(xiàn)1818條經(jīng)驗(yàn) 獲得超7個(gè)贊
有沒(méi)有辦法將 func(string) string 類(lèi)型的現(xiàn)有函數(shù)轉(zhuǎn)換為 func(interface{}) interface{} 類(lèi)型,以便它也可以傳遞給裝飾器函數(shù),而無(wú)需將其包裝在新的匿名函數(shù)中(見(jiàn) funcB)?
不,就這么簡(jiǎn)單:不。
- 4 回答
- 0 關(guān)注
- 178 瀏覽
添加回答
舉報(bào)