英文:
How to use a struct field into another struct without referring to it as a key
问题
我想在另一个结构体中插入一个结构体字段,而不必使用结构体名称。
我知道可以这样做:
type Person struct {
Name string
}
type User struct {
Person
Email, Password string
}
但这会导致以下结构体:
user := User{Person: Person{Name: ""}, Email: "", Password: ""}
我该如何做到像这样:
type Person struct {
Name string
}
type User struct {
Name Person.Name // 这里
Email, Password string
}
以便像这样使用它:
user := User{Name: "", Email: "", Password: ""}
这种做法可行吗?
英文:
I want to insert a struct field into another struct without having to use the struct name.
I know that I can do this:
type Person struct {
Name string
}
type User struct {
Person
Email, Password string
}
But It results in this struct:
user := User{Person: Person{Name: ""}, Email: "", Password: ""}
How can I do something like this:
type Person struct {
Name string
}
type User struct {
Name Person.Name // Here
Email, Password string
}
To use it like this
user := User{Name: "", Email: "", Password: ""}
Is it possible?
答案1
得分: 1
简单来说,根据当前的语言实现,你无法以你期望的方式初始化内部的Person
。
当初始化一个字面量时,你需要明确指定(或者说:字面量!)。由于User
包含一个Person
,一个字面量的User
必须包含一个字面量的Person
,就像你所示例的那样:
u := User{
Person: Person{
Name: "Bob",
},
Email: "bob@bobspot.com",
Password: "you're kidding right?",
}
然而,一旦你有了一个类型为User
的变量,你可以利用匿名字段来设置(或获取)匿名Person
的Name
,如下所示:
u := User{}
u.Name = "Bob"
u.Email = "bob@bobspot.com",
u.Password = "you're kidding right?",
为什么Go要让我做这么多工作?
让我们想象一下,如果可以以你期望的方式初始化内部的Person
:
u := User{ Name: "Bob" }
现在让我们进一步想象,我们稍后修改User
结构并添加它自己的Name
字段:
type User struct {
Person
Name string
Email string
Password string
}
现在你可以明显地初始化新的Name
字段:
u := User{ Name: "Bob" }
注意,这与之前初始化User.Person.Name
的代码是相同的,但现在它初始化的是User.Name
。这样不好。
更多陷阱
使用这样的代码还有其他潜在的问题。
首先,向User
变量的未限定引用添加一个Name
字段已经类似地“破坏”了对User
变量上的Name
的设置:
u.Name = "Bob" // 用于设置User.Person.Name,现在设置的是User.Name
此外,只有一个匿名的Person
字段时,默认情况下,User.Person.Name
字段会被默认地转换为JSON的“Name”字段:
{
"Name": "",
"Email": "",
"Password": ""
}
如果添加一个Name
字段,那么这个字段将作为"Name"
被转换为JSON,而User.Person.Name
字段将根本不会被转换。
你可能会认为可以为User.Person.Name
添加一个json
标签,例如:
type User struct {
Person `json:"PersonName"`
Name string
Email string
Password string
}
但是现在Person
将被转换为一个带有Name
字段的对象:
{
"PersonName": {
"Name": ""
},
"Name": "",
"Email": "",
"Password": ""
}
即使User
没有Name
字段,如果你尝试更改匿名Person
的转换字段名,也会发生这种情况。
简而言之:在结构体中使用匿名结构体作为“添加字段”的方式可能存在问题,而且可能很脆弱,应该尽量避免使用。
英文:
Simply put, with the current language implementation you can't.
When initialising a literal you need to be explicit (or, put another way: literal! [sic]). Since a User
contains a Person
, a literal User
must contain a literal Person
, as you illustrate:
u := User{
Person: Person{
Name: "Bob",
},
Email: "bob@bobspot.com",
Password: "you're kidding right?",
}
However, once you have a variable of type User
, you can then leverage the anonymous field to set (or get) the Name
of the anonymous Person
with the User
:
u := User{}
u.Name = "Bob"
u.Email = "bob@bobspot.com",
u.Password = "you're kidding right?",
Why Does Go Make Me Do All This Work?
Let us imagine that it was possible to initialise the inner Person
in the way you are looking for:
u := User{ Name: "Bob" }
Now let us further imagine that we later modify the User
struct and add its own Name
field:
type User struct {
Person
Name string
Email string
Password string
}
And now you can obviously initialise the new Name
field:
u := User{ Name: "Bob" }
Notice that this is identical to the previous code that initialised User.Person.Name
but now it is initialising User.Name
. Not good.
More Gotchas
There are further traps lurking with code like this.
First, the addition of a Name
field in User
already similarly "breaks" unqualified references to Name
on User
variables:
u.Name = "Bob" // used to set User.Person.Name, now sets User.Name
Also, with only an anonymous Person
field, the User.Person.Name
field is marshalled to JSON by default as a "Name" field:
{
"Name": "",
"Email": "",
"Password": ""
}
If a Name
field is added, then this is the field that is marshalled as "Name"
and the User.Person.Name
field is not marshalled at all.
You might think you can add a json
tag for the User.Person.Name
, e.g.
type User struct {
Person `json:"PersonName"`
Name string
Email string
Password string
}
But now the Person
is marshalled as an object with a Name
field:
{
"PersonName": {
"Name": ""
},
"Name": "",
"Email": "",
"Password": ""
}
This also happens if you try to change the marshalled field name of the anonymous Person
even if User
does not have a Name
field.
In short: using anonymous structs within structs as a way of "adding fields" is potentially problematic and fragile and should probably be avoided.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论