Skip to content

Instantly share code, notes, and snippets.

@jamesrr39
Last active February 19, 2019 04:05
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jamesrr39/84b6d6c65c3d16a6aa47 to your computer and use it in GitHub Desktop.
Save jamesrr39/84b6d6c65c3d16a6aa47 to your computer and use it in GitHub Desktop.
Go Pointers

Go pointers

This gist demonstrates the use of pointers in go (and other similar languages)

Use &x to get the address of x

Use *x to get a value from an address x

When should I use a pointer?

  • When you want to pass a variable to a function, to change something on the variable (perform a side-effect on the variable)
  • When you have a large object that you want to pass between functions, it is more performant to pass a pointer around rather than copy a large object any times -- on a 64 bit machine, a pointer will take 8 bytes (64 bits / 8 bits in a byte)

When should I not use a pointer?

  • When you want to protect against modifications to the original variable

Generally it comes down to a trade off between protecting against modifications to the original variable (immutability) and performance of copying the variable.

See some examples in action:

go run go-pointers.go
package main
import (
"fmt"
"unsafe"
)
func main() {
demoString()
demoStruct()
}
func demoString() {
x := "abc"
pointerToX := &x
copyOfX := x
fmt.Println("\n> First, we create 3 variables: x (a string), pointerToX (a pointer to x), and copyOfX (a string, copied from x)")
fmt.Printf("X value: %s, held at %p\n", x, &x)
fmt.Printf("pointerToX value (address of the pointer in memory): %p. Value at this address: %s\n", pointerToX, *pointerToX)
fmt.Printf("copyOfX value: %s, held at %p\n", copyOfX, &copyOfX)
// change x
fmt.Println("\n> Now we change the value of x")
x = "abcdef"
fmt.Printf("X value: %s, held at %p\n", x, &x)
fmt.Printf("pointerToX value (address of the pointer in memory): %p. Value at this address: %s\n", pointerToX, *pointerToX)
fmt.Printf("copyOfX value: %s, held at %p\n", copyOfX, &copyOfX)
fmt.Printf("> Note that pointerToX points to the new value of '%s', whereas copyOfX made a copy of the value of x, so is still '%s'\n", *pointerToX, copyOfX)
fmt.Println("\n> How much memory does each value take?")
fmt.Printf("x takes: %d bytes\n", unsafe.Sizeof(x))
fmt.Printf("pointerToX takes %d bytes\n", unsafe.Sizeof(pointerToX))
fmt.Printf("copyOfX takes %d bytes\n\n", unsafe.Sizeof(copyOfX))
}
type coordinate struct {
x string
y *string
}
func demoStruct() {
fmt.Println("\n> How about a struct (z) with a pointer?")
y := "z_pointer"
z := coordinate{
x: "z_string",
y: &y,
}
fmt.Printf("z.x value: '%s', held at %p\n", z.x, &z.x)
fmt.Printf("z.y value: '%s', held at %p\n", *z.y, z.y)
fmt.Printf("z takes: %d bytes\n", unsafe.Sizeof(z))
fmt.Printf("z.x takes: %d bytes\n", unsafe.Sizeof(z.x))
fmt.Printf("z.y takes: %d bytes\n", unsafe.Sizeof(z.y))
fmt.Println("\n> How about copying a struct with a pointer?")
copyOfZ := z
fmt.Printf("copyOfZ.x is '%s', held at %p\n", copyOfZ.x, &copyOfZ.x)
fmt.Printf("copyOfZ.y is '%s', held at %p\n", *copyOfZ.y, copyOfZ.y)
fmt.Println("\n> What happens the original struct if we change the values in the copied struct?")
y = "copyOfZ_pointer_modified"
copyOfZ.x = "copyOfZ_string_modified"
fmt.Printf("z.x is '%s'\n", z.x)
fmt.Printf("z.y is '%s'\n", *z.y)
fmt.Println("> The string field is unaffected, is it has been copied. However the pointer z.y is now pointing to 'copyOfZ_string_modified'.")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment