Golang learning journal — (2) pointers — when to pass by pointer, when to pass by value?

Shelly
4 min readSep 30, 2022

--

Photo by Nick Fewings on Unsplash

Introduction

Hi there! I am Shelly, a non-CS background developer since 2020. This article belongs to my Golang learning journal series. For all the related articles, you can find the links in the table of contents at the very first article of this series.

Pointers — what are stars (*) and ampersand (&)?

Let’s first talk about the two signs that we can’t avoid when it comes to pointers: * and & .

Star (*) has 2 meanings

(1) Operator — when it’s in front of a variable — e.g. below * is in front of a variable p.
-
This will give you the underlying value of the variable

var a = 66
p := &a
fmt.Println(*p) // the "*" before "p" is an Operator. This will print out 66 (the value)

(2) Signifying that it’s a pointer — when it’s in front of a type— e.g. below * is in front of a type string.
-
often used at function declaration

// the "*" before "string" is saying that "hey, this is a pointer to a string, not the string itself"
func someFunc(pointerA *string) {}

Ampersand (&) has only 1 meaning

(1) Operator — when in front of a variable — e.g. below & is in front of a variablea. This will give you the address of the variable.
- often used at passing value to a function that has pointer as one of it’s inputs’ type

var a = 66
p := &a // the "&" before "p" is an Operator.
fmt.Println(p) // This will print out 0x1400011c028 (the address)

Remember that *type is often used in the function declaration? For such a function with *type as input, we need to pass &variable as value when calling that function.

func someFunc(pointerA *string) {} // when declaring functionfunc main() {
var a string
someFunc(&a) // when calling the function
}

If you accidently passed value using *, i.e. calling someFunc(*a)rather than someFunc(&a), you will get:
invalid operation: cannot indirect a(variable of type string).

Let’s see some example where we can combine * and & :

// e.g. 1
stringA := "Hello"
fmt.Println(*&stringA) // "Hello"
// e.g. 2 when assigning new value to a field of a struct
structAPointer = &structA
(*structAPointer).attributeX = "New Value"

When to pass by pointer

When many functions manipulate the original object. So you don’t need to copy it many times.

When to pass by value itself

If there is no special needs, go prefers pass by value itself rather than pass by pointer, to avoid extra overhead of Escape Analysis and crash due to nil pointer.

An example of pass by pointer

to illustrate how we use all 3 usage explained above:
*variable — operator, *type — signifying that it’s a pointer, and &variable — operator.

func main() {
var wholeString []string
addString(&wholeString, "new1") // &wholeString is address
addString(&wholeString, "new2")
wholeString= append(wholeString, "new3") // do not need pointer since it's still in the scope of where wholeString is declared
fmt.Println("end wholeString: \n", wholeString)
}
func addString (wholeStringPointer *[]string, newString string) {
*wholeStringPointer = append(*wholeStringPointer, newString)
addMoreString(wholeStringPointer)
}
func addMoreString (wholeStringPointer *[]string) {
var moreString = "~~~and more"
*wholeStringPointer = append(*wholeStringPointer, moreString)
}
func addEvenMoreString(wholeStringPointer *[]string) {
var evenMoreString = "~~~even more\n"
*wholeStringPointer = append(*wholeStringPointer, evenMoreString)
}

Above code will print out:

end wholeString: 
[new1 ~~~and more ~~~even more
new2 ~~~and more ~~~even more
new3]

Although we are talking about pass by pointer, theoretically, go do not have pass bypointer . Everything is pass byvalue . The pointerin this article means that it’s value is the pointer to an address. Hence, in our example above, since the input of addString() , addMoreString() , and addEvenMoreString()are all*[]string , which is a pointer type. We do use the technique of pass by pointer (the pointer value, aka the address)to change the variable’s underlying value in an upper scope.

Next article: go commnds — go get, go install, go mod download, go mod tidy — when to use what?

Thanks for reading till here. If you found the article helpful, feel free to clap multiple times on the article (one person can clap up to 50 times!), or ❤️ give me some tips following the below link ❤️. Thank you in advance :)

You are also welcome to clap for this article through liker land, so I can receive some coins on the blockchain! :)

--

--