英文:
Assign struct with another struct
问题
我有一个RegistrationRequest结构体:
type RegistrationRequest struct {
Email *string
Email2 *string
Username *string
Password *string
Name string
}
其中Email2
是再次输入的电子邮件值,用于验证用户输入的是否正确。
我还有一个User结构体:
type User struct {
Email *string
Username *string
Password *string
Name string
}
当然,在注册之后没有必要存储Email2
。
所以我有两个变量:req
和u
- 分别对应这两个结构体。是否可以将req
结构体赋值给u
结构体,以便u
结构体中存在所有共同的字段?
英文:
I have a RegistrationRequest struct:
type RegistrationRequest struct {
Email *string
Email2 *string
Username *string
Password *string
Name string
}
Where Email2
is the email value entered again to verify that what the user entered is correct.
I also have a User struct:
type User struct {
Email *string
Username *string
Password *string
Name string
}
Of course, there is no need to store Email2
beyond registration.
So I have two variables: req
and u
- one for each struct. Is it possible to assign the req
struct into to the u
struct so that all the common fields will exist in the u
struct?
答案1
得分: 33
使用简单的赋值语句是无法实现的,因为尽管User
的字段是RegistrationRequest
的子集,但它们是完全不同的类型,不适用可赋值性规则。
你可以编写一个使用反射(reflect
包)的函数,将req
的所有字段复制到u
,但这样做很丑陋(而且效率低下)。
最好的方法是重构你的类型,并且RegistrationRequest
可以嵌入User
。
这样做的话,如果你有一个RegistrationRequest
类型的值,那么你已经有了一个User
类型的值:
type User struct {
Email *string
Username *string
Password *string
Name string
}
type RegistrationRequest struct {
User // 嵌入User类型
Email2 *string
}
func main() {
req := RegistrationRequest{}
s := "as@as.com"
req.Email = &s
s2 := "testuser"
req.Username = &s2
u := User{}
u = req.User
fmt.Println(*u.Username, *u.Email)
}
输出结果:(在Go Playground上尝试)
testuser as@as.com
请注意,由于你的结构体包含指针,当复制一个结构体时,指针值将被复制,而不是指向的值。我不确定为什么你在这里需要指针,最好将所有字段声明为非指针。
还请注意,嵌入并不是真正的要求,它只是使你的类型及其使用更加顺畅。User
也可以作为RequistrationRequest
的一个普通字段,例如:
type RegistrationRequest struct {
Usr User // 这只是一个普通字段,不是嵌入
Email2 *string
}
英文:
Using simple assignment you can't because even though the fields of User
are a subset of RegistrationRequest
, they are completely 2 different types, and Assignability rules don't apply.
You could write a function which uses reflection (reflect
package), and would copy all the fields from req
to u
, but that is just ugly (and inefficient).
Best would be to refactor your types, and RegistrationRequest
could embed User
.
Doing so if you have a value of type RegistrationRequest
that means you already also have a value of User
:
type User struct {
Email *string
Username *string
Password *string
Name string
}
type RegistrationRequest struct {
User // Embedding User type
Email2 *string
}
func main() {
req := RegistrationRequest{}
s := "as@as.com"
req.Email = &s
s2 := "testuser"
req.Username = &s2
u := User{}
u = req.User
fmt.Println(*u.Username, *u.Email)
}
Output: (try it on the Go Playground)
testuser as@as.com
Also please note that since your structs contain pointers, when copying a struct
, pointer values will be copied and not pointed values. I'm not sure why you need pointers here, would be best to just declare all fields to be non-pointers.
Also note that embedding is not really a requirement, it just makes your types and their usage more smooth. User
could just as well be an "ordinary" field of RequistrationRequest
, e.g.:
type RegistrationRequest struct {
Usr User // This is just an ordinary field, not embedding
Email2 *string
}
答案2
得分: 5
你可以使用"github.com/jinzhu/copier"包来在包含相同字段名称的结构体之间进行复制。该包使用反射来实现这一功能。
package main
import (
"fmt"
"github.com/jinzhu/copier"
)
type RegistrationRequest struct {
Email *string
Email2 *string
Username *string
Password *string
Name string
}
type User struct {
Email *string
Username *string
Password *string
Name string
}
func main() {
user := new(User)
req := new(RegistrationRequest)
user.Email, user.Password, user.Username = new(string), new(string), new(string)
user.Name = "John Doe"
*user.Email = "a@b.com"
*user.Password = "1234"
*user.Username = "johndoe"
fmt.Println("User :", user.Name, *user.Email, *user.Username, *user.Password)
copier.Copy(req, user)
fmt.Println("RegistrationRequest :", req.Name, *req.Email, *req.Username, *req.Password)
}
输出结果:
User : John Doe a@b.com johndoe 1234
RegistrationRequest : John Doe a@b.com johndoe 1234
英文:
You can use "github.com/jinzhu/copier" package to Copy between structs containing same field name. This package uses reflection to do this.
package main
import (
"fmt"
"github.com/jinzhu/copier"
)
type RegistrationRequest struct {
Email *string
Email2 *string
Username *string
Password *string
Name string
}
type User struct {
Email *string
Username *string
Password *string
Name string
}
func main() {
user := new(User)
req := new(RegistrationRequest)
user.Email, user.Password, user.Username = new(string), new(string), new(string)
user.Name = "John Doe"
*user.Email = "a@b.com"
*user.Password = "1234"
*user.Username = "johndoe"
fmt.Println("User :",user.Name, *user.Email, *user.Username, *user.Password)
copier.Copy(req, user)
fmt.Println("RegistrationRequest :",req.Name, *req.Email, *req.Username, *req.Password)
}
Output
User : John Doe a@b.com johndoe 1234
RegistrationRequest : John Doe a@b.com johndoe 1234
答案3
得分: 0
func ObjectAssign(target interface{}, object interface{}) {
// 将 object 的属性值赋给 target 的属性值
// 使用模式匹配(https://golang.org/pkg/reflect/#Value.FieldByName)
// 参考:https://stackoverflow.com/questions/35590190/how-to-use-the-spread-operator-in-golang
t := reflect.ValueOf(target).Elem()
o := reflect.ValueOf(object).Elem()
for i := 0; i < o.NumField(); i++ {
for j := 0; j < t.NumField(); j++ {
if t.Field(j).Name() == o.Field(i).Name() {
t.Field(j).Set(o.Field(i))
}
}
}
}
英文:
func ObjectAssign(target interface{}, object interface{}) {
// object atributes values in target atributes values
// using pattern matching (https://golang.org/pkg/reflect/#Value.FieldByName)
// https://stackoverflow.com/questions/35590190/how-to-use-the-spread-operator-in-golang
t := reflect.ValueOf(target).Elem()
o := reflect.ValueOf(object).Elem()
for i := 0; i < o.NumField(); i++ {
for j := 0; j < t.NumField(); j++ {
if t.Field(j).Name() == o.Field(i).Name() {
t.Field(j).Set(o.Field(i))
}
}
}
}
答案4
得分: 0
如果第二个结构体是第一个结构体的克隆,并且字段较少,你可以通过json来转换结构体。
type user1 struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
UserName string `json:"user_name"`
}
type user2 struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
}
...
u1Json, _ := json.Marshal(u1)
_ = json.Unmarshal(u1Json, &u2)
以上是代码的翻译部分。
英文:
If the second structure is a clone of the first one with fewer fields you can convert the structures via json.
type user1 struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
UserName string `json:"user_name"`
}
type user2 struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
}
...
u1Json, _ := json.Marshal(u1)
_ = json.Unmarshal(u1Json,&u2)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论