Pola swojej anonimowej typu struct są unexported. Oznacza to, że nie można tworzyć wartości tej struktury i określać wartości dla pól z innego pakietu. Spec: Composite literals:
Błędem jest podanie elementu dla niewyeksportowanego pola struktury należącego do innego pakietu.
Jeśli zmienisz definicję struktury, aby wyeksportować pola, to zadziała, ponieważ wszystkie pola mogą być przypisane do innych pakietów (patrz Siu Ching Pong - odpowiedź Assuki Kenji).
Jest tak również w przypadku pustej struktury (bez pól): pusta struktura nie ma pól, więc nie ma nieodportowanych pól, więc możesz przekazać jej wartość.
Możesz jednak wywołać funkcję z niezmodyfikowaną strukturą (z nieodportowanymi polami) przez reflection. Możesz uzyskać reflect.Type
funkcji PrintAnonymous()
i możesz użyć Type.In()
, aby uzyskać reflect.Type
pierwszego parametru. To jest anonimowa struktura, dla której chcemy przekazać wartość. I możesz skonstruować wartość tego typu za pomocą reflect.New()
. Będzie to reflect.Value
, zawijanie wskaźnika do zero value anonimowej struktury. Niestety, nie możesz mieć wartości struct z polami o wartościach niezerowych (z powodów wymienionych powyżej).
ten sposób mogłoby to wyglądać tak:
v := reflect.ValueOf(somepackage.PrintAnonymous)
paramt := v.Type().In(0)
v.Call([]reflect.Value{reflect.New(paramt).Elem()})
ten wypisze:
0:
0
jest zerowa wartość dla int
i ""
pusty ciąg dla string
.
Dla głębiej do systemu typu i kodowanym z polami unexported, zobaczyć inne pytania:
Identify non builtin-types using reflect
How to clone a structure with unexported field?
ciekawe (jest to błąd zobacz połączony problem poniżej), używając refleksji, możesz użyć wartości własnego anonimowego typu struktury (z dopasowaniem, Pola unexported), w tym przypadku możemy użyć wartości inne niż wartość zerową pól struct:
value := struct {
i int
s string
}{
1, "Hello, world!",
}
v.Call([]reflect.Value{reflect.ValueOf(value)})
Wyżej przebiegów (bez paniki):
1: Hello, world!
Powodem jest to dozwolone jest z powodu błędu w kompilatorze. Zobacz przykładowy kod poniżej:
s := struct{ i int }{2}
t := reflect.TypeOf(s)
fmt.Printf("Name: %q, PkgPath: %q\n", t.Name(), t.PkgPath())
fmt.Printf("Name: %q, PkgPath: %q\n", t.Field(0).Name, t.Field(0).PkgPath)
t2 := reflect.TypeOf(subplay.PrintAnonymous).In(0)
fmt.Printf("Name: %q, PkgPath: %q\n", t2.Name(), t2.PkgPath())
fmt.Printf("Name: %q, PkgPath: %q\n", t2.Field(0).Name, t2.Field(0).PkgPath)
wyjścia:
Name: "", PkgPath: ""
Name: "i", PkgPath: "main"
Name: "", PkgPath: ""
Name: "i", PkgPath: "main"
Jak widać pole unexported i
w obu anonimowych typów struct (w main
opakowaniu iw somepackage
jako parametr do PrintAnonymous()
funkcyjnego) - fałszywie - zgłoś to samo opakowanie, a tym samym ich typ będzie równy:
fmt.Println(t == t2) // Prints true
Uwaga: uważam to za skaza: jeśli pozwala na to odbicie, powinno to być możliwe bez użycia refleksji. Jeśli bez refleksji błąd kompilacji jest uzasadniony, użycie refleksji powinno spowodować panikę w czasie wykonywania. Otworzyłem problem, możesz to zrobić tutaj: issue #16616. Fix aktualnie ma cel Go 1.8.
Co się stanie, jeśli wielkie litery będą miały właściwości struct? struct {I int S string} – Dale
@Dalej: Tak! Właśnie to zauważyłem! Dzięki! Jak głupio jestem! –