2

I have a slice of struct []student, and I want to modify its content with function.

type student struct {
    name string
    age int
}

students := []student{
    {"Doraemon", 30},
    {"King Kong", 25},
}

Thus, I decided to pass it as a pointer. May I know how to pass the slice as a reference to a function?

func addAge (s *[]student) error { //this code has error
    //everyone add 2 years old
    for i, e := range *s {
        s[i].age = s[i].age + 2
    }
    //make the first student much older
    s[0].age = s[0].age + 5
    return nil
}

I keep playing with Go Playground, but it gives many complains, such as

cannot range over s (type *[]student)
invalid operation: s[i] (type *[]student does not support indexing)
invalid indirect of s
...

How to precisely pass the reference of a slice of struct to a function? How to range the slice of struct? And how to change the value of the struct (modify the same struct in THE slice)?

I keep getting error while playing with s *[]student, range *s, s []student, s *[]*student ... so hard to get it correct...

sorry for my NEWBIE question, still learning GO... trying hard

Boo Yan Jiong
  • 2,491
  • 5
  • 17
  • 31
  • 1
    Please show us the _exact code_ with your _exact_ error. It's hard to tell you how to improve your code when you have different, conflicting error messages. – Jonathan Hall Dec 18 '17 at 19:51
  • 4
    Also, you shouldn't need to pass a pointer to a slice--slices are already passed by reference. – Jonathan Hall Dec 18 '17 at 19:51
  • 1
    you **must** read that, https://blog.golang.org/slices. Slice is quiet special thing. –  Dec 18 '17 at 20:18

2 Answers2

4

Slices are passed by reference, so as long as you are modifying the existing slice content you should not explicitly pass a pointer.

package main

import (
    "fmt"
)

type student struct {
    name string
    age int
}

func main() {
    students := []student{
        {"Doraemon", 30},
        {"King Kong", 25},
    }

    err := addAge (students)

    fmt.Println(students)
    if err != nil {
        fmt.Println("error")
    }
}

func addAge (s []student) error {
    for i, _ := range s {
        s[i].age = 3
    }
    return nil
}

Now, for your addAdditinalStudent function you should actually use the append function. Plus, have in mind

..., since the slice header is always updated by a call to append, you need to save the returned slice after the call. In fact, the compiler won't let you call append without saving the result. Slices#append

// add student
students = append(students, student{"Test", 33})

Go Playground

Vane Trajkov
  • 758
  • 4
  • 11
2

in Go you can pass items by value ([]student) or by reference ([]*student). When you want to operate on the values of a struct{} you should pass it to a function with its reference (the pointer).

So you can do something like this:

type student struct {
    name string
    age int
}

func addTwoYearsToAll(students []*student){
  for _, s := range students {
        s.age += 2
     }
}

This way you're working with the same exact items you build when appending to the slice. Playground example.

Also take a look at Are Golang function parameter passed as copy-on-write?

Francesco Gualazzi
  • 919
  • 1
  • 10
  • 23
  • 1
    That's not valid, `s` is an integer. If `s` were a `*student`, you don't dereference `s.age`, because `age` isn't a pointer. – JimB Dec 18 '17 at 20:07