Identifiziere nicht eingebaute Typen mit reflect

8

Ich muss solche Typen wie

unterscheiden %Vor%

von einem []byte . Mit reflect , reflect.TypeOf(A{}).Kind wird mir mitgeteilt, dass es sich um Slice von byte handelt. Wie kann ich []byte{} von A{} unterscheiden, ohne eine beschränkte Typenliste zu haben?

Gibt es neue Möglichkeiten, dies in neueren Go-Versionen zu tun?

    
Matt Joiner 30.03.2016, 13:37
quelle

1 Antwort

9

Etwas Hintergrund

Lassen Sie uns zuerst einige Dinge im Zusammenhang mit Typen klären. Zitieren von Spec: Typen:

  

Ein Typ bestimmt die Menge von Werten und Operationen, die für Werte dieses Typs spezifisch sind. Typen können benannt oder unbenannt sein. Benannte Typen werden von einem (möglicherweise qualifizierten ) Typname ; unbenannte Typen werden mit einem Literal type angegeben, das aus vorhandenen Typen einen neuen Typ zusammensetzt.

Es gibt also (vordefinierte) benannte Typen wie string , int etc, und Sie können auch neue benannte Typen mit Typdeklarationen (mit dem Schlüsselwort type ) wie type MyInt int . Und es gibt unbenannte Typen , die das Ergebnis eines literalen -Typs sind (angewendet auf / einschließlich benannter oder unbenannter Typen), wie zB []int , struct{i int} , *int usw.

Sie können den Namen eines benannten Typs mit der Type.Name() -Methode abrufen, die "zurückgibt eine leere Zeichenfolge für unbenannte Typen ":

%Vor%

Es gibt Typen, die vordefiniert sind und Ihnen zur Verfügung stehen (entweder wie sie sind oder in Typliteralen):

  

Benannte Instanzen der Booleschen, numerischen und Zeichenfolientypen sind vordeklariert . Zusammengesetzte Typen - Array-, Struct-, Pointer-, Funktions-, Interface-, Slice-, Map- und Channel-Typen - können mithilfe von Typliteralen erstellt werden.

Vorgegebene Typen sind:

%Vor%

Sie können Type.PkgPath() verwenden, um den Paketpfad eines benannten -Typs zu erhalten "Wenn der Typ vordefiniert wurde ( string , error ) oder unbenannt ( *T , struct{} , []int ), ist der Paketpfad die leere Zeichenfolge" :

%Vor%

Damit stehen Ihnen zwei Werkzeuge zur Verfügung: Type.Name() , um zu erkennen, ob der Typ ein benannter -Typ ist, und Type.PkgPath() , um festzustellen, ob der Typ nicht vorbelegt und ist ein benannter Typ .

Aber Vorsicht ist geboten. Wenn Sie einen eigenen, benannten Typ in einem Typliteral verwenden, um einen neuen Typ zu erstellen (zB []A ), wird dies ein unbenannter Typ (wenn Sie das type -Schlüsselwort nicht verwenden, um einen neuen, benannten Typ zu konstruieren) :

%Vor%

Was können Sie in solchen Fällen tun? Sie können Type.Elem() verwenden, um den Elementtyp des Typs abzurufen, wenn Kind des Typs Array ,% co_de ist %, Chan , Map oder Ptr (sonst Slice Panics):

%Vor%

Zusammenfassung

Mit

Type.Elem() können vordeklarierte und unbenannte Typen "herausgefiltert" werden. Wenn Type.PkgPath() eine nicht leere Zeichenfolge zurückgibt, können Sie sicher sein, dass es sich um einen benutzerdefinierten Typ handelt. Wenn es eine leere Zeichenfolge zurückgibt, ist es möglicherweise ein unbenannter Typ (in diesem Fall PkgPath() gibt Type.Name() zurück), der aus einem "benutzerdefinierten" Typ erstellt wurde. Dazu können Sie "" verwenden, um festzustellen, ob es aus einem "benutzerdefinierten" Typ besteht, der möglicherweise rekursiv angewendet werden muss:

%Vor%

Probiere alle Beispiele auf dem Gehe Spielplatz aus.

Sonderfall # 1: Anonyme Strukturtypen

Es gibt auch den Fall eines anonymen Strukturtyps, der unbenannt ist, aber möglicherweise ein Feld eines "benutzerdefinierten" Typs hat. Dieser Fall kann behandelt werden, indem man über die Felder des Strukturtyps iteriert und die gleiche Prüfung für jedes Feld durchführt, und wenn einer von ihnen ein "benutzerdefinierter" Typ ist, können wir behaupten, dass der gesamte Strukturtyp "benutzerdefiniert" ist. .

Spezialfall # 2: Kartentypen

Im Fall von Karten können wir einen unbenannten Kartentyp als "benutzerdefiniert" betrachten, wenn einer seiner Schlüssel- oder Werttypen "benutzerdefiniert" ist.

Der Werttyp einer Map kann mit der oben genannten Type.Elem() -Methode abgefragt werden, und der Schlüsseltyp einer Map kann mit der Type.Elem() -Methode abgefragt werden - dies müssen wir auch bei Maps überprüfen.

Beispielimplementierung

%Vor%

Testen Sie es (versuchen Sie es auf dem Go Playground ):

%Vor%     
icza 18.05.2016, 07:09
quelle

Tags und Links