網頁

2021/8/19

Golang 在for loop修改struct元素的屬性

Go在for迴圈中修改struct slice的元素屬性的方式如下。


範例環境:

  • Go 1.16

這可能是初學Golang的常見問題,for迴圈struct slice要修改每個struct元素的屬性,但發現無法修改。

例如下面在foreach(Go的for range語法)中遍歷slice emps中的每個Employee元素並將Age加1,但迴圈結束後值未被修改。

main.go

package main

import "fmt"

type Employee struct {
    Id   int
    Name string
    Age  int
}

func main() {
    emps := []Employee{
        {Id: 1, Name: "John", Age: 33},
        {Id: 1, Name: "Mary", Age: 28},
    }

    for _, emp := range emps {
        emp.Age = emp.Age + 1
    }

    fmt.Println(emps) // [{1 John 33} {1 Mary 28}]
}

或是用一般的for迴圈也是無法修改struct的屬性值。

package main

import "fmt"

type Employee struct {
    Id   int
    Name string
    Age  int
}

func main() {
    emps := []Employee{
        {Id: 1, Name: "John", Age: 33},
        {Id: 1, Name: "Mary", Age: 28},
    }

    for i := 0; i < len(emps); i++ {
        emp := emps[i]
        emp.Age = emp.Age + 1
    }

    fmt.Println(emps) // [{1 John 33} {1 Mary 28}]
}

上面的原因在於slice取出元素時是複製一份再分派到變數e,所以原本的slice元素並沒有被修改。

因此for迴圈中slice取出元素前可加上&取得指向該元素的指標

main.go

package main

import "fmt"

type Employee struct {
    Id   int
    Name string
    Age  int
}

func main() {
    emps := []Employee{
        {Id: 1, Name: "John", Age: 33},
        {Id: 1, Name: "Mary", Age: 28},
    }
    for i := 0; i < len(emps); i++ {
        emp := &emps[i] // get pointer of emps[i]
        emp.Age = emp.Age + 1
    }

    fmt.Println(emps) // [{1 John 34} {1 Mary 29}]
}

也可修改成以下類似JavaScript forEach的味道。

main.go

package main

import (
    "fmt"
)

type Employee struct {
    Id   int
    Name string
    Age  int
}

func main() {
    emps := []Employee{
        {Id: 1, Name: "John", Age: 33},
        {Id: 1, Name: "Mary", Age: 28},
    }

    foreach(emps, func(emp *Employee) {
        emp.Age = emp.Age + 1
    })

    fmt.Println(emps) // [{1 John 34} {1 Mary 29}]
}

func foreach(emps []Employee, apply func(emp *Employee)) {
    for i := 0; i < len(emps); i++ {
        emp := &emps[i]
        apply(emp)
    }
}


沒有留言:

張貼留言