Reputation: 10693
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?
Upvotes: 27
Views: 56950
Reputation: 189
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)
Upvotes: 0
Reputation: 1
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))
}
}
}
}
Upvotes: 0
Reputation: 91
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 = "[email protected]"
*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 [email protected] johndoe 1234
RegistrationRequest : John Doe [email protected] johndoe 1234
Upvotes: 5
Reputation: 418435
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 := "[email protected]"
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 [email protected]
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
}
Upvotes: 34