tommyd456
tommyd456

Reputation: 10693

Assign struct with another struct

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

Answers (4)

Krzysztof Czerwiński
Krzysztof Czerwiński

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

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

Prasanna Mahajan
Prasanna Mahajan

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

icza
icza

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

Related Questions