Rumah > Artikel > pembangunan bahagian belakang > Bagaimana untuk membuat instantiate penuding bukan sifar kepada parameter jenis menggunakan Go generik?
editor php Xigua akan memperkenalkan kepada anda cara menggunakan penunjuk bukan sifar bagi parameter jenis instantiasi generik dalam bahasa Go. Dalam bahasa Go, generik ialah ciri berkuasa yang boleh meningkatkan fleksibiliti dan kebolehgunaan semula kod. Apabila kita perlu membuat instantiat penunjuk bukan sifar dalam fungsi atau kaedah generik, kita boleh menggunakan penegasan jenis dan refleksi untuk mencapai ini. Dengan menggunakan teknik ini, kita boleh mencipta contoh penuding bukan sifar pada masa jalan berdasarkan jenis parameter jenis tertentu, dengan itu mencapai fleksibiliti dan serba boleh generik. Mari kita lihat dengan lebih dekat kaedah pelaksanaan khusus.
Sekarang parameter jenis tersedia pada golang/go:master
, saya memutuskan untuk mencubanya. Nampaknya saya telah mencapai had yang saya tidak dapati dalam cadangan parameter jenis. (Atau saya pasti merinduinya).
Saya ingin menulis fungsi yang mengembalikan sepotong nilai jenis generik dengan kekangan jenis antara muka. Jika jenis yang diluluskan ialah pelaksanaan dengan penerima penuding, bagaimanakah kita hendak membuat instantiat?
type SetGetter[V any] interface { Set(V) Get() V } // SetGetterSlice turns a slice of type V into a slice of type T, // with T.Set() called for each entry in values. func SetGetterSlice[V any, T SetGetter[V]](values []V) []T { out := make([]T, len(values)) for i, v := range values { out[i].Set(v) // panic if T has pointer receiver! } return out }
Apabila menggunakan *Count
类型作为 T
调用上述 SetGetterSlice()
函数时,此代码将在调用 Set(v)
时出现混乱。 (Go2go 游乐场)毫不奇怪,因为基本上代码创建了 nil
hirisan penunjuk:
// Count implements SetGetter interface type Count struct { x int } func (c *Count) Set(x int) { c.x = x } func (c *Count) Get() int { return c.x } func main() { ints := []int{1, 2, 3, 4, 5} sgs := SetGetterSlice[int, *Count](ints) for _, s := range sgs { fmt.Println(s.Get()) } }
Idea ini tidak berfungsi, saya nampaknya tidak dapat mencari cara mudah untuk menyatakan nilai yang ditunjukkan.
out[i] = new(T)
将导致编译失败,因为它返回 *T
,其中类型检查器希望查看 T
. *new(T)
进行编译,但会导致相同的运行时恐慌,因为 new(T)
返回 **Count
在这种情况下,其中指向 Count
的指针仍然是 nil
. T
akan menyebabkan kompilasi gagal: func SetGetterSlice[V any, T SetGetter[V]](values []V) []*T { out := make([]*T, len(values)) for i, v := range values { out[i] = new(T) out[i].Set(v) // panic if T has pointer receiver } return out } func main() { ints := []int{1, 2, 3, 4, 5} SetGetterSlice[int, Count](ints) // Count does not satisfy SetGetter[V]: wrong method signature }
Satu-satunya penyelesaian yang saya temui setakat ini ialah memerlukan penghantaran pembina kepada fungsi generik. Tapi rasa salah dan agak bosan. Jika func F(T interface{})() []T
ialah sintaks yang betul-betul sah, mengapakah ia diperlukan?
func SetGetterSlice[V any, T SetGetter[V]](values []V, constructor func() T) []T { out := make([]T, len(values)) for i, v := range values { out[i] = constructor() out[i].Set(v) } return out } // ... func main() { ints := []int{1, 2, 3, 4, 5} SetGetterSlice[int, *Count](ints, func() *Count { return new(Count) }) }
Soalan saya (mengikut keutamaan):
Pada asasnya, anda perlu menambah parameter jenis pada kekangan untuk menjadikan T
boleh ditukar kepada jenis penunjuknya. Dalam bentuk yang paling asas, teknik ini kelihatan seperti ini (dengan kekangan tanpa nama):
func Foo[T any, PT interface { *T; M() }]() { p := PT(new(T)) p.M() // calling method on non-nil pointer }
Taman permainan:https://www.php.cn/link/24aef8cb3281a2422a59b51659f1ad2e
Penyelesaian langkah demi langkah
Kekangan anda SetGetter
已经声明了类型参数 V
, jadi kami mengubah suai contoh di atas sedikit:
// V is your original type param // T is the additional helper param type SetGetter[V any, T any] interface { Set(V) Get() V *T }
Kemudian tentukan SetGetterSlice
函数,其类型参数为 T any
,其目的只是实例化约束 SetGetter
.
Anda kemudian boleh menghantar ungkapan &out[i]
kepada jenis penunjuk dan berjaya memanggil kaedah pada penerima penunjuk:
// T is the type with methods with pointer receiver // PT is the SetGetter constraint with *T func SetGetterSlice[V any, T any, PT SetGetter[V, T]](values []V) []T { out := make([]T, len(values)) for i, v := range values { // out[i] has type T // &out[i] has type *T // PT constraint includes *T p := PT(&out[i]) // valid conversion! p.Set(v) // calling with non-nil pointer receiver } return out }
Program penuh:
CFE57E536C89530D9A8C38E10967A10DIni menjadi lebih bertele-tele kerana SetGetterSlice
kini memerlukan tiga jenis parameter: V
tambah SetGetterSlice
现在需要三个类型参数:原始 V
加上 T
(带有指针接收器的类型)和 PT
(新约束)。然而,当您调用该函数时,您可以省略第三个 - 通过类型推断,实例化 PT SetGetter[V,T]
所需的类型参数 V
和 T
(jenis dengan penerima penunjuk) dan PT ( kekangan baru). Walau bagaimanapun, apabila anda memanggil fungsi tersebut, anda boleh meninggalkan yang ketiga - melalui jenis inferens, parameter jenis <code>V
yang diperlukan untuk membuat instantiate PT SetGetter[V,T]
dan
SetGetterSlice[int, Count](ints)Taman permainan:https://www.php.cn/link/6b061fc28f7473418a006dfa832708b1🎜
Atas ialah kandungan terperinci Bagaimana untuk membuat instantiate penuding bukan sifar kepada parameter jenis menggunakan Go generik?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!