这是一段[play.google.org](https://play.golang.org/p/nk9HBJAMO3)可以毫无问题运行的代码:
[play.google.org](https://play.golang.org/p/nk9HBJAMO3)
package main import ( "fmt" ) func PrintAnonymous(v struct { i int s string }) { fmt.Printf("%d: %s\n", v.i, v.s) } func PrintAnonymous2(v struct{}) { fmt.Println("Whatever") } func main() { value := struct { i int s string }{ 0, "Hello, world!", } PrintAnonymous(value) PrintAnonymous2(struct{}{}) }
但是,如果该PrintAnonymous()函数存在于另一个包中(例如temp),则该代码将不起作用:
PrintAnonymous()
temp
cannot use value (type struct { i int; s string }) as type struct { i int; s string } in argument to temp.PrintAnonymous
我的问题是:
PrintAnonymous2()
好吧,我知道我总是可以命名struct来解决问题,我对此感到很好奇,并且想知道为什么似乎不允许这样做。
struct
您的匿名结构类型的字段未导出。这意味着您无法创建该结构的值,也无法为另一个包中的字段指定值。规格:复合文字:
为属于不同包的结构的非导出字段指定元素是错误的。
如果您更改结构定义以导出字段,那么它将起作用,因为所有字段都可以由其他程序包分配(请参见Siu Ching Pong -Asuka Kenji-的答案)。
空结构(也没有字段)也是如此:空结构没有字段,因此没有未导出的字段,因此您可以传递该值。
但是,您可以通过反射使用未经修改的结构(具有未导出的字段)来调用该函数。你可以得到reflect.Type的的PrintAnonymous()功能,并且可以使用Type.In()来获取reflect.Type它的第一个参数。那就是我们要传递值的匿名结构。您可以使用构造该类型的值reflect.New()。这将是一个reflect.Value,包装指向匿名结构零值的指针。抱歉,您的结构值不能包含非零值的字段(由于上述原因)。
reflect.Type
Type.In()
reflect.New()
reflect.Value
它看起来像这样:
v := reflect.ValueOf(somepackage.PrintAnonymous) paramt := v.Type().In(0) v.Call([]reflect.Value{reflect.New(paramt).Elem()})
这将打印:
0:
0是的零值int,和的""空字符串string。
0
int
""
string
有趣的是( 这是一个错误 ,请参见下面的链接问题),通过反射,您可以使用自己的匿名结构类型的值(具有匹配的未导出字段),在这种情况下,我们可以使用除0之外的其他值。结构域:
value := struct { i int s string }{ 1, "Hello, world!", } v.Call([]reflect.Value{reflect.ValueOf(value)})
高于跑步次数(无需惊慌):
1: Hello, world!
允许这样做的原因是由于编译器中的错误。请参见下面的示例代码:
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)
输出为:
Name: "", PkgPath: "" Name: "i", PkgPath: "main" Name: "", PkgPath: "" Name: "i", PkgPath: "main"
如您所见i,两种匿名结构类型中的未导出字段(在main包中以及somepackage作为PrintAnonymous()函数的参数)–错误地–报告相同的包,因此它们的类型将相等:
i
main
somepackage
fmt.Println(t == t2) // Prints true
注意:我认为这是一个 缺陷 :如果允许使用反射,则应该也可以不使用反射。如果在没有反射的情况下证明了编译时错误,那么使用反射会导致运行时出现恐慌。我为此打开了一个问题,您可以在此处关注它:Issue#16616。Fix当前针对Go1.8。