Slice element not updated in go

和自甴很熟 提交于 2020-12-13 20:59:13

问题


I have an account struct as below:

type Account struct {
    Id       string
    Name     string
    Address  string
    City     string
    Email    string
    Phone    string
    Username string
    Password string
    IsActive bool
}

I also have two function: find and update. The find function find certain element from the slice and return the pointer to the element:

func find(accounts []Account, username string) *Account {
    for _, acc := range accounts {
        if acc.IsActive && acc.Username == username {
            return &acc
        }
    }
    return nil
}

The update function change certain field from the params:

func update(account *Account, name string) {
    account.Name = name
}

In main, i try to find an element from the slice and store it to a pointer of account. Then, i try to update a field in the next line. This is how my main looks like:

func main() {
    accounts := []Account{{
        Id:       "1",
        Name:     "name",
        Address:  "address",
        City:     "city",
        Email:    "email@email.com",
        Phone:    "123456789",
        Username: "username",
        Password: "1234",
        IsActive: true,
    }}
    var acc *Account
    acc = find(accounts, "username")
    fmt.Printf("%v\n", accounts)
    fmt.Println(acc)

    update(acc, "updated")
    fmt.Printf("%v\n", accounts)
    fmt.Println(acc)
}

The problem is when update called, the element in slice is not updated. It just update the data of stored account. Below is the output of main:

// find
[{1 name address city email@email.com 123456789 username 1234 true}]
&{1 name address city email@email.com 123456789 username 1234 true}

// update
[{1 name address city email@email.com 123456789 username 1234 true}]
&{1 updated address city email@email.com 123456789 username 1234 true}

How to make the element inside the slice updated when the store element changed? Thank you for your help, any suggestion would be appreciate.


回答1:


issue is you are returning copy of element rather than actual address of the element in the array

return &acc

change your find function as below

func find(accounts []Account, username string) *Account {
for idx , acc := range accounts {
    if acc.IsActive && acc.Username == username {
        return &accounts[idx]
    }
}
return nil
}

your will get the expected response

[{1 name address city email@email.com 123456789 username 1234 true}]
&{1 name address city email@email.com 123456789 username 1234 true}
[{1 updated address city email@email.com 123456789 username 1234 true}]
&{1 updated address city email@email.com 123456789 username 1234 true}

you can check the updated code here in go playground




回答2:


in this code,

func find(accounts []Account, username string) *Account {
    for _, acc := range accounts {
        if acc.IsActive && acc.Username == username {
            return &acc
        }
    }
    return nil
}

Because the slice you are iterating is of type []Account, each acc value you get is a copy of the value stored in the slice. Thus, the acc value you are referencing is not the value stored in your slice.

To prevent that behavior, use a slice of pointer, ie: []*Account.

Refrain from referencing the slice index as demonstrated in this play, you will run into bugs. https://play.golang.org/p/orgA8nCw2yc



来源:https://stackoverflow.com/questions/65095052/slice-element-not-updated-in-go

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!