Last active
December 22, 2019 10:13
-
-
Save geberl/db975428f8aaed74097835bfeeaff16e to your computer and use it in GitHub Desktop.
Pointers vs literals & Swift-style safe unwrapping
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import "fmt" | |
type person struct { | |
firstName string | |
lastName *string | |
addressAsValue address | |
addressAsPointer *address | |
childrenAsSlice []person | |
childrenAsPointer *[]person | |
} | |
type address struct { | |
city string | |
zip uint32 | |
} | |
// String is a convenienve for converting a string literal to a pointer to a string. | |
func String(s string) *string { return &s } | |
// Int is a convenience for converting an int literal to a pointer to an int. | |
func Int(i int) *int { return &i } | |
// Int32 is a convenience for converting an int32 literal to a pointer to an int32. | |
func Int32(i int32) *int32 { return &i } | |
// Bool is a convenience for converting a bool literal to a pointer to a bool. | |
func Bool(b bool) *bool { return &b } | |
func main() { | |
firstPerson := person{firstName: "jim", lastName: String("beam")} | |
// firstAddr := address{city: "munich", zip: 80000} | |
// firstPerson := person{firstName: "jim", lastName: String("beam"), addressAsPointer: &firstAddr} | |
fmt.Println(firstPerson) // {jim 0xc000010200 { 0} <nil> [] <nil>} | |
fmt.Println("---") | |
fmt.Println(firstPerson.firstName) // jim | |
fmt.Println(firstPerson.lastName) // 0xc0000621e0 | |
fmt.Println(*firstPerson.lastName) // beam | |
fmt.Println("---") | |
// This works in both cases | |
fmt.Println(firstPerson.addressAsValue) // { 0} = default value empty string for string and 0 for uint32 | |
fmt.Println(firstPerson.addressAsPointer) // <nil> = default value nil for pointer | |
fmt.Println(firstPerson.childrenAsSlice) // [] = default value empty slice for slice | |
fmt.Println(firstPerson.childrenAsPointer) // <nil> = default value nil for pointer | |
fmt.Println("---") | |
// Going one level deeper just works for values, not for pointers | |
fmt.Println(firstPerson.addressAsValue.zip) // 0 | |
// fmt.Println(firstPerson.addressAsPointer.zip) // "panic: runtime error: invalid memory address or nil pointer dereference" | |
fmt.Println("---") | |
// Compare Swift pattern for safe-unwrapping of optional: | |
// var title: String? | |
// if let safeTitle = title { | |
// ... | |
// } | |
// Swift-style "safe-unwrapping", only possible if defined as pointer | |
if addr := firstPerson.addressAsPointer; addr != nil { | |
fmt.Println(addr.zip) | |
} | |
// This works and as expected prints nothing because the slice is empty | |
for _, child := range firstPerson.childrenAsSlice { | |
fmt.Println(child.firstName) | |
} | |
// This is invalid code, "cannot range over firstPerson.childrenAsPointers", a pointer is a single memory address | |
// for _, child := range firstPerson.childrenAsPointer { | |
// fmt.Println(child.firstName) | |
// } | |
// Dereferencing the pointer leads to valid code but throws "panic: runtime error: invalid memory address or nil pointer dereference" if the slice is empty | |
// for _, child := range *firstPerson.childrenAsPointer { | |
// fmt.Println(child.firstName) | |
// } | |
// - Underneath a slice is already a kind of pointer (pointer to first element + length of slice + capacity of slice) | |
// - Explicitly using a pointer to a slice "*[]" is useless in terms of reducing the memory footprint | |
// - And it might cause the program to fatally error if someone decides to dereference the pointer and range over it | |
// - *[] is kind of a code smell | |
// - There is only one legit use for pointer to a slice: | |
// If multiple sections of the program need to share the same slice | |
// So modifications to the slice itself are reflected in other sections of the program | |
// This is rarely what you want, however, and is not thread-safe without locking | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment