我有一個采用泛型型別的函式,并且應該回傳一個始終回傳指標的函式。即,如果你傳遞給它一個非指標型別,它應該回傳一個指向該型別的指標,如果你傳遞一個指標型別它應該回傳相同的型別。我不想使用它,reflect.New因為它是一個性能關鍵的應用程式。
我不介意在回傳工廠函式的函式中使用反射,但理想情況下甚至不在那里。
這就是我想要做的:
package main
import (
"fmt"
"reflect"
)
type Ptr[T any] interface {
*T
}
func makeNewA[T Ptr[U], U any]() any {
return new(U)
}
func makeNewB[T any]() any {
return new(T)
}
func makeNew[T any](v T) func() any {
if reflect.TypeOf(v).Kind() == reflect.Ptr {
return makeNewA[T] // <-- error: T does not match *U
} else {
return makeNewB[T]
}
}
type Foo struct{}
func main() {
make1 := makeNew(Foo{})
make2 := makeNew(&Foo{})
// should both return &Foo{}
fmt.Println(make1())
fmt.Println(make2())
}
uj5u.com熱心網友回復:
這種條件型別不能用泛型很好地解決,因為當你實體化時T any,*Foo你會丟失有關基本型別的資訊。事實上,您的代碼仍然使用反射和any(= interface{}),并且makeN函式的回傳型別必須被型別斷言為*Foo.
您可以使用當前代碼獲得的最接近的是:
func makeNew[T any](v T) func() any {
if typ := reflect.TypeOf(v); typ.Kind() == reflect.Ptr {
elem := typ.Elem()
return func() any {
return reflect.New(elem).Interface() // must use reflect
}
} else {
return func() any { return new(T) } // v is not ptr, alloc with new
}
}
然后兩個 maker 函式都將回傳一個any包裝非 nil值的*Foo值:
fmt.Printf("%T, %v\n", make1(), make1()) // *main.Foo, &{}
fmt.Printf("%T, %v\n", make2(), make2()) // *main.Foo, &{}
游樂場:https ://gotipplay.golang.org/p/kVUM-qVLLHG
進一步的考慮:
return makeNewA[T]在您的第一次嘗試中不起作用,因為條件reflect.TypeOf(v).Kind() == reflect.Ptr是在運行時評估的,而實體化makeNewA發生在編譯時。在編譯時T僅受限制any并且any(=interface{}) 沒有實作Ptr[U]- 您無法僅使用引數捕獲有關指標型別和基本型別的資訊
v。例如makeNew[T Ptr[U], U any](v T),呼叫時不會編譯,makeNew(Foo{})并且makeNew[T Ptr[U], U any](v U)會推斷T為**Foo呼叫時*Foo
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/443004.html
