英文:
Scope visibility of struct members while passing as a argument?
问题
在调用json.Decoder.Decode时,通过传递一个结构体,例如:
type _Sample struct {
first string // 这个字段不会被填充,因为它以小写字母开头
Second string // 这个字段是可以的
}
...
var sample _Sample
err := decoder.Decode(&sample)
根据语言规范的说明:
导出的标识符:
为了允许从另一个包中访问标识符,可以将其导出。如果满足以下两个条件,则标识符被导出:
- 标识符的名称的第一个字符是一个Unicode大写字母(Unicode类别“Lu”);
- 标识符在包块中声明,或者它是字段名或方法名。
所有其他标识符都不会被导出。
问题是_Sample
结构体并没有被导出,为什么它可以被json
包访问到呢?
英文:
While calling json.Decoder.Decode by passing a struct, for instance
type _Sample struct {
first string // this will not be filled because it starts with lower case letter
Second string // it is OK.
}
...
var sample _Sample
err := decoder.Decode(&sample)
According to the Language Specification that writes:
> Exported identifiers ¶
>
> An identifier may be exported to permit access to it from another package. An identifier is exported if both:
>
> - the first character of the identifier's name is a Unicode upper case letter (Unicode class "Lu"); and
> - the identifier is declared in the package block or it is a field name or method name.
>
>
> All other identifiers are not exported.
The question is the struct _Sample
is not exported, why it is visible by the package json
?
答案1
得分: 3
访问权限 在以下情况下进行检查:
- 当你创建/声明一个变量时,编译器会检查类型标识符的名称的可见性。
- 使用
reflect
包来修改一个变量。 - 调用一个常量、全局变量或函数。将检查常量/变量/函数名称的可见性。
一旦变量被创建/定义,并且当你将这个变量作为函数/方法的参数传递时,副本(如果是值类型,则复制值;如果是指针类型,则复制地址)将被传递给函数/方法,并且始终可以通过参数名称和类型从函数体中访问。在 encoding/json
包中,Decoder.Decode
方法被定义为:
func (dec *Decoder) Decode(v interface{}) error
因此,你传递给 Decoder.Decode
方法的任何内容都可以通过参数 v
在方法体内部访问。请注意,v
的类型是 interface{}
而不是 _Sample
结构体。可见性在你定义变量时进行检查,例如:
var sample _Sample
这是可以的,因为它是在同一个包内部完成的。甚至匿名结构体(即结构体没有定义类型名称标识符)也可以正常工作,例如:
aSample := struct {
first string // 这个字段不会被填充,因为它以小写字母开头
Second string // 这是可以的
}{}
//...
err := decoder.Decode(&aSample)
接下来,当 decoder
填充结构体(通过反射),将会检查结构体成员的可见性,而 _Sample.first
在 json
包内部是不可见的。
英文:
Access permission is checked when
- You're creating/declaring a variable. The compiler will check the visibility of the name of the type identifier.
- Using
reflect
package to modify a variable. - Calling a constant, global variable, or a function. The visibility of constant/variable/function name will be checked.
Once the variable is created/defined, and when you pass this variable as a function/method argument, the copy (If it is a value, the value is being copied. If it is a pointer, the address is being copied) will be passed to the function/method, and always accessible from the function body through the argument name and type. In encoding/json
package, the Decoder.Decode
method is defined as,
func (dec *Decoder) Decode(v interface{}) error
thus, anything you passed to the Decoder.Decode
method, is always accessible from inside the method body through argument v
. Note that the type of v
is interface{}
not _Sample
struct. The visibility is checked when you defined the variable as
var sample _Sample
which was OK since it is done from within the same package. Even an anonymous struct (i.e. no type name identifier is defined for the struct)
aSample := struct {
first string // this will not be filled because it starts with lower case letter
Second string // it is OK.
}{}
//...
err := decoder.Decode(&aSample)
will works. Next, when the decoder
fills the struct (through reflection), the visibility of struct members will be checked, and _Sample.first
is not visible from inside the json
package.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论