Heim > Artikel > Backend-Entwicklung > Wie instanziiere ich mit einem generischen Go einen Zeiger ungleich Null auf einen Typparameter?
php-Editor Xigua zeigt Ihnen, wie Sie Nicht-Null-Zeiger für generische Instanziierungstypparameter in der Go-Sprache verwenden. In der Go-Sprache sind Generika eine leistungsstarke Funktion, die die Flexibilität und Wiederverwendbarkeit von Code erhöhen kann. Wenn wir in einer generischen Funktion oder Methode einen Zeiger ungleich Null instanziieren müssen, können wir dies mithilfe von Typzusicherungen und -reflexionen erreichen. Mithilfe dieser Techniken können wir zur Laufzeit eine Zeigerinstanz ungleich Null basierend auf dem spezifischen Typ des Typparameters erstellen und so die Flexibilität und Vielseitigkeit von Generika erreichen. Schauen wir uns die spezifische Implementierungsmethode genauer an.
Da nun Typparameter auf golang/go:master
verfügbar sind, habe ich beschlossen, es auszuprobieren. Es scheint, dass ich auf eine Einschränkung gestoßen bin, die ich im Vorschlag für Typparameter nicht finden kann. (Oder ich muss es verpasst haben).
Ich möchte eine Funktion schreiben, die einen Ausschnitt generischer Typwerte mit Schnittstellentypbeschränkungen zurückgibt. Wenn der übergebene Typ eine Implementierung mit einem Zeigerempfänger ist, wie instanziieren wir ihn?
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 }
Bei Verwendung von *Count
类型作为 T
调用上述 SetGetterSlice()
函数时,此代码将在调用 Set(v)
时出现混乱。 (Go2go 游乐场)毫不奇怪,因为基本上代码创建了 nil
Zeigerscheiben:
// 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()) } }
Diese Idee funktioniert nicht, ich kann anscheinend keinen einfachen Weg finden, den angegebenen Wert zu instanziieren.
out[i] = new(T)
将导致编译失败,因为它返回 *T
,其中类型检查器希望查看 T
. *new(T)
进行编译,但会导致相同的运行时恐慌,因为 new(T)
返回 **Count
在这种情况下,其中指向 Count
的指针仍然是 nil
. T
führt dazu, dass die Kompilierung fehlschlägt: 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 }
Die einzige Lösung, die ich bisher gefunden habe, besteht darin, die Übergabe des Konstruktors an eine generische Funktion zu verlangen. Aber es fühlt sich falsch und ein bisschen langweilig an. Wenn func F(T interface{})() []T
eine vollkommen gültige Syntax ist, warum wird sie dann benötigt?
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) }) }
Meine Fragen (in der Reihenfolge ihrer Priorität):
Grundsätzlich müssen Sie der Einschränkung einen Typparameter hinzufügen, um T
in seinen Zeigertyp konvertierbar zu machen. In ihrer einfachsten Form sieht die Technik so aus (mit Einschränkungen der Anonymität):
func Foo[T any, PT interface { *T; M() }]() { p := PT(new(T)) p.M() // calling method on non-nil pointer }
Spielplatz:https://www.php.cn/link/24aef8cb3281a2422a59b51659f1ad2e
Schritt-für-Schritt-Lösung
Ihre Einschränkungen SetGetter
已经声明了类型参数 V
, daher modifizieren wir das obige Beispiel leicht:
// V is your original type param // T is the additional helper param type SetGetter[V any, T any] interface { Set(V) Get() V *T }
Dann definieren Sie SetGetterSlice
函数,其类型参数为 T any
,其目的只是实例化约束 SetGetter
.
Sie können dann den Ausdruck &out[i]
in einen Zeigertyp umwandeln und die Methode erfolgreich auf dem Zeigerempfänger aufrufen:
// 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 }
Volles Programm:
CFE57E536C89530D9A8C38E10967A10DDies wird ausführlicher, da SetGetterSlice
jetzt drei Typparameter erfordert: das ursprüngliche V
plus SetGetterSlice
现在需要三个类型参数:原始 V
加上 T
(带有指针接收器的类型)和 PT
(新约束)。然而,当您调用该函数时,您可以省略第三个 - 通过类型推断,实例化 PT SetGetter[V,T]
所需的类型参数 V
和 T
(der Typ mit dem Zeigerempfänger) und PT ( neue Einschränkung). Wenn Sie die Funktion jedoch aufrufen, können Sie den dritten weglassen – durch Typinferenz die Typparameter <code>V
, die zum Instanziieren von PT SetGetter[V,T]
erforderlich sind und
SetGetterSlice[int, Count](ints)Spielplatz:https://www.php.cn/link/6b061fc28f7473418a006dfa832708b1🎜
Das obige ist der detaillierte Inhalt vonWie instanziiere ich mit einem generischen Go einen Zeiger ungleich Null auf einen Typparameter?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!