Home > Enterprise >  golang: change value of struct while iterating over struct array/slice with range()
golang: change value of struct while iterating over struct array/slice with range()

Time:03-13

I have struct with array in it as example below

type WorkPlace struct {
    Employees []struct {
        Name    string `json:"name"`
        Salary  int    `json:"salary"`
        Married bool   `json:"married"`
    } `json:"employees"`
}
{
    "employees": [
        {  
            "name":       "sonoo1",   
            "salary":      49000,   
            "married":    true  
        },
        {
            "name":       "sonoo2",   
            "salary":      59000,   
            "married":    true  
        }
    ]  
}  

and let say I wanna change the value of Salary while iterating over the slice of Employees.

So way that allow me to modify the fields in that struct is that i have to use the standard for loop as example which works:

for i := 0; i < len(myWorkPlace.Employees); i   {
        rise := rand.Intn(100)   i
        myWorkPlace.Employees[i].Salary  = rise
    }

but if i do "same thing" with using range the values are not changed:

for i, v := range myWorkPlace.Employees {
      rise := rand.Intn(100)   i
      v.Salary  = rise
}

from what i am reading i see that range is doing a copy of the array/slice that why the values are not modified ... BUT is there way to access the array/slice or tell range to do this on same array/slice (by using pointers ??) so i can modify the field as in first loop ?

https://go.dev/ref/spec#RangeClause

CodePudding user response:

Please check this two ways

package main

import (
    "fmt"
)

type Student struct {
    Name  string
    Marks int
}

func main() {

    // slice of non-pointers
    students := []Student{Student{Name: "A", Marks: 10}, Student{Name: "B", Marks: 12}, Student{Name: "C", Marks: 14}}
    fmt.Printf("Before Update==%v", students)

    //using range to update non-pointer struct

    for i, v := range students {
        students[i].Marks = v.Marks   2
    }
    fmt.Printf("\nAfter Update==%v", students)

    // slice of pointers
    studentsV2 := []*Student{&Student{Name: "A", Marks: 10}, &Student{Name: "B", Marks: 12}, &Student{Name: "C", Marks: 14}}

    fmt.Println("\nBefore Update==")

    for _, v := range studentsV2 {
        fmt.Printf("%v", v)
    }
    //using range to update pointer struct

    for _, v := range studentsV2 {
        v.Marks = v.Marks   2
    }

    fmt.Println("\nAfter Update==")

    for _, v := range studentsV2 {
        fmt.Printf("%v", v)
    }

}

CodePudding user response:

@Pratheesh M please have look at this example which is showing the problem which i did ask above:

package main

import (
    "encoding/json"
    "fmt"
    "math/rand"
)

type WorkPlace struct {
    Employees []Employees `json:"employees"`
}
type Employees struct {
    Name    string `json:"name"`
    Salary  int    `json:"salary"`
    Married bool   `json:"married"`
}

var (
    pln = fmt.Println
    pf  = fmt.Printf
)

func main() {
    myWorkPlace := WorkPlace{
        []Employees{
            {
                Name:    "sonoo1",
                Salary:  49000,
                Married: true,
            },
            {
                Name:    "sonoo2",
                Salary:  59000,
                Married: true,
            },
        },
    }

    j, _ := myWorkPlace.Pretty()
    pf("Before Update: \n%v\n", j)

    for i, v := range myWorkPlace.Employees {
        rise := rand.Intn(100)   i
        v.Salary  = rise
    }
    j1, _ := myWorkPlace.Pretty()
    pf("After Update using range: \n%v\n", j1)

    for i := 0; i < len(myWorkPlace.Employees); i   {
        rise := rand.Intn(100)   i
        myWorkPlace.Employees[i].Salary  = rise
    }
    j2, _ := myWorkPlace.Pretty()
    pf("After Update without of range: \n%v\n", j2)
}

func (wp *WorkPlace) Pretty() (string, error) {
    j, err := json.MarshalIndent(&wp, " ", "   ")
    if err != nil {
        return "", err
    }
    return string(j), nil
}

Output:

Before Update: 
{
    "employees": [
       {
          "name": "sonoo1",
          "salary": 49000,
          "married": true
       },
       {
          "name": "sonoo2",
          "salary": 59000,
          "married": true
       }
    ]
 }
After Update using range: 
{
    "employees": [
       {
          "name": "sonoo1",
          "salary": 49000,
          "married": true
       },
       {
          "name": "sonoo2",
          "salary": 59000,
          "married": true
       }
    ]
 }
After Update without of range: 
{
    "employees": [
       {
          "name": "sonoo1",
          "salary": 49047,
          "married": true
       },
       {
          "name": "sonoo2",
          "salary": 59060,
          "married": true
       }
    ]
 }

https://go.dev/play/p/xgENiLIdISG

So my question is still same or maybe i did get what you @Pratheesh M trying to show me with your example ... so maybe you could apply your idea to my code example and make the for loop "working as expected".

  • Related