l'éditeur php Xigua vous présentera comment utiliser des pointeurs non nuls de paramètres de type d'instanciation génériques en langage Go. Dans le langage Go, les génériques constituent une fonctionnalité puissante qui peut augmenter la flexibilité et la réutilisabilité du code. Lorsque nous devons instancier un pointeur différent de zéro dans une fonction ou une méthode générique, nous pouvons utiliser des assertions de type et une réflexion pour y parvenir. En utilisant ces techniques, nous pouvons créer une instance de pointeur non nulle au moment de l'exécution en fonction du type spécifique du paramètre de type, obtenant ainsi la flexibilité et la polyvalence des génériques. Examinons de plus près la méthode de mise en œuvre spécifique.
Maintenant que les paramètres de type sont disponibles sur golang/go:master
, j'ai décidé de l'essayer. Il semble que j'ai atteint une limitation que je ne trouve pas dans la proposition de paramètres de type. (Ou j'ai dû le manquer).
Je souhaite écrire une fonction qui renvoie une tranche de valeurs de type générique avec des contraintes de type d'interface. Si le type transmis est une implémentation avec un récepteur de pointeur, comment l'instancier ?
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 }
Lors de l'utilisation de *Count
类型作为 T
调用上述 SetGetterSlice()
函数时,此代码将在调用 Set(v)
时出现混乱。 (Go2go 游乐场)毫不奇怪,因为基本上代码创建了 nil
tranches de pointeurs :
// 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()) } }
Cette idée ne fonctionne pas, je n'arrive pas à trouver un moyen simple d'instancier la valeur indiquée.
out[i] = new(T)
将导致编译失败,因为它返回 *T
,其中类型检查器希望查看 T
. *new(T)
进行编译,但会导致相同的运行时恐慌,因为 new(T)
返回 **Count
在这种情况下,其中指向 Count
的指针仍然是 nil
. T
entraînera l'échec de la compilation : 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 }
La seule solution que j'ai trouvée jusqu'à présent est d'exiger le passage du constructeur à une fonction générique. Mais cela semble faux et un peu ennuyeux. Si func F(T interface{})() []T
est une syntaxe parfaitement valide, pourquoi est-elle nécessaire ?
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) }) }
Mes questions (par ordre de priorité) :
Fondamentalement, vous devez ajouter un paramètre de type à la contrainte pour rendre T
convertible en son type de pointeur. Dans sa forme la plus basique, la technique ressemble à ceci (avec des contraintes d'anonymat) :
func Foo[T any, PT interface { *T; M() }]() { p := PT(new(T)) p.M() // calling method on non-nil pointer }
Aire de jeux :https://www.php.cn/link/24aef8cb3281a2422a59b51659f1ad2e
<小时>Solution étape par étape
Vos contraintes SetGetter
已经声明了类型参数 V
, nous modifions donc légèrement l'exemple ci-dessus :
// V is your original type param // T is the additional helper param type SetGetter[V any, T any] interface { Set(V) Get() V *T }
Puis définissez SetGetterSlice
函数,其类型参数为 T any
,其目的只是实例化约束 SetGetter
.
Vous pouvez ensuite convertir l'expression &out[i]
en type pointeur et appeler avec succès la méthode sur le récepteur du pointeur :
// 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 }
Programme complet :
CFE57E536C89530D9A8C38E10967A10DCela devient plus détaillé car SetGetterSlice
nécessite désormais trois paramètres de type : le V
d'origine plus SetGetterSlice
现在需要三个类型参数:原始 V
加上 T
(带有指针接收器的类型)和 PT
(新约束)。然而,当您调用该函数时,您可以省略第三个 - 通过类型推断,实例化 PT SetGetter[V,T]
所需的类型参数 V
和 T
(le type avec le récepteur du pointeur) et PT< /code> ( nouvelle contrainte). Cependant, lorsque vous appelez la fonction, vous pouvez omettre la troisième inférence de type, les paramètres de type <code>V
requis pour instancier PT SetGetter[V,T]
et
SetGetterSlice[int, Count](ints)
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!