gpt4 book ai didi

go - 以匿名结构作为参数导出函数[不能在 package.Func 的参数中使用值(类型 struct {...})作为类型 struct {...}]

转载 作者:IT老高 更新时间:2023-10-28 13:05:17 24 4
gpt4 key购买 nike

这是一段代码 play.google.org 运行没有任何问题:

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),则代码将不起作用:

cannot use value (type struct { i int; s string })
as type struct { i int; s string } in argument to temp.PrintAnonymous

我的问题是:

  • 有没有办法以匿名结构作为参数调用(公共(public))函数(又名 PrintAnonymous())?
  • 一个以空结构体为参数的函数(也就是上面的PrintAnonymous2())即使存在于另一个包中也可以被调用。这是特例吗?

好吧,我知道我总是可以命名 struct 来解决问题,我只是对此感到好奇,想知道为什么似乎不允许这样做。

最佳答案

您的匿名结构类型的字段未导出。这意味着您不能创建此结构的值并为另一个包中的字段指定值。 Spec: Composite literals:

It is an error to specify an element for a non-exported field of a struct belonging to a different package.

如果您更改结构定义以导出字段,那么它将起作用,因为所有字段都可以由其他包分配(参见 Siu Ching Pong -Asuka Kenji-'s answer)。

空结构(没有字段)也是如此:空结构没有字段,因此它没有未导出的字段,因此您可以传递它的值。

您可以通过 reflection 调用具有未修改结构(带有未导出字段)的函数尽管。您可以获取reflect.Type PrintAnonymous() 函数,您可以使用 Type.In() 来获取其第一个参数的 reflect.Type。那就是我们要为其传递值的匿名结构。您可以使用 reflect.New() 构造该类型的值.这将是 reflect.Value , 包装指向 zero value 的指针的匿名结构。抱歉,你不能有一个字段值非零的结构值(出于上述原因)。

这就是它的样子:

v := reflect.ValueOf(somepackage.PrintAnonymous)
paramt := v.Type().In(0)
v.Call([]reflect.Value{reflect.New(paramt).Elem()})

这将打印:

0: 

0int 的零值,""string 的空字符串。

要深入了解类型系统和具有未导出字段的结构,请参阅相关问题:

Identify non builtin-types using reflect
How to clone a structure with unexported field?


有趣的是(这是一个错误,请参阅下面的链接问题),使用反射,您可以使用您自己的匿名结构类型的值(具有匹配的、未导出的字段),在这种情况下,我们可以使用结构字段的零值以外的值:

value := struct {
i int
s string
}{
1, "Hello, world!",
}

v.Call([]reflect.Value{reflect.ValueOf(value)})

上面运行(没有 panic ):

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() 函数)——错误地——报告相同的包,因此它们的类型将相等:

fmt.Println(t == t2) // Prints true

注意:我认为这是一个缺陷:如果允许使用反射,那么在不使用反射的情况下也应该可以。如果没有反射编译时错误是合理的,那么使用反射应该会导致运行时 panic 。我为此开了一个问题,你可以在这里关注它:issue #16616 .修复当前的目标是 Go 1.8。

关于go - 以匿名结构作为参数导出函数[不能在 package.Func 的参数中使用值(类型 struct {...})作为类型 struct {...}],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38784963/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com