这是一段代码 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
我的问题是:
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:
0 是 int 的零值,"" 是 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/
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
我怎样才能完成http://php.net/manual/en/function.call-user-func-array.php在ruby中?所以我可以这样做:classAppdeffoo(a,b)putsa+benddefbarargs=[1,2]App.send(:foo,args)#doesn'tworkApp.send(:foo,args[0],args[1])#doeswork,butdoesnotscaleendend 最佳答案 尝试分解数组App.send(:foo,*args)
exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby中使用两个参数异步运行exe吗?我已经尝试过ruby命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何rubygems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除
我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere
我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"
我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re
我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串
我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)
两者都可以defsetup(options={})options.reverse_merge:size=>25,:velocity=>10end和defsetup(options={}){:size=>25,:velocity=>10}.merge(options)end在方法的参数中分配默认值。问题是:哪个更好?您更愿意使用哪一个?在性能、代码可读性或其他方面有什么不同吗?编辑:我无意中添加了bang(!)...并不是要询问nobang方法与bang方法之间的区别 最佳答案 我倾向于使用reverse_merge方法:option
我正在尝试用ruby中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了