Pointers in Go: Difference between revisions
Tag: Reverted |
|||
Line 57: | Line 57: | ||
fmt.Printf("%#v\n", b) // will print "(*int)(nil)" | fmt.Printf("%#v\n", b) // will print "(*int)(nil)" | ||
</syntaxhighlight> | </syntaxhighlight> | ||
[[Go_Language#Type_Assertions|Type assertions]] can be used to programmatically decide if a variable is a pointer: | |||
=Displaying Pointers= | =Displaying Pointers= |
Revision as of 20:23, 8 May 2024
External
Internal
TODO
Further reading:
- https://medium.com/@meeusdylan/when-to-use-pointers-in-go-44c15fe04eac
- https://www.ardanlabs.com/blog/2013/07/understanding-pointers-and-memory.html
- https://go.dev/doc/faq#Pointers
Overview
A pointer is a data type that represents a virtual address in memory, usually the address of a location in memory that is referred by a variable.
A pointer can be declared as such:
var aPtr *int // a pointer to an int
A pointer can also be implicitly declared using the short variable declaration and the the referencing operator inside functions:
a := 10
aPtr := &a
aPtr
is a variable that contains the memory address of the memory location associated with the variable a
. Changing the memory value using a syntax that involves the pointer will surface in the value of the variable:
*aPtr = 20
println(a) // will display 20
Escape Analysis
Once a non-nil
value is assigned to a pointer, the Go runtime guarantees that the thing being pointed to will continue to be valid for the life time of the pointer. This allows for a pattern when what looks like a stack variable can be allocated inside a function, and a pointer to it returned outside the function. The pointer will remain valid even if the stack is unwound, the compiler will arrange for the memory location holding the value of i to be valid after the function return. This is done with escape analysis, which is the process of determining whether a variable should be stored on stack or on the heap:
func makeInt() *int {
i := 10
return &i
}
go build -gcflags="-m" cmd/acmd.go [...] cmd/acmd.go:4:2: moved to heap: i
How to Tell if a Variable is a Pointer
Use reflect.TypeOf()
on the variable. If the variable is a pointer, displaying the result of reflect.TypeOf()
will start with "*":
var b *int
fmt.Println(reflect.TypeOf(b)) // will print "*int"
Alternatively, use:
fmt.Printf("%#v\n", b) // will print "(*int)(nil)"
Type assertions can be used to programmatically decide if a variable is a pointer:
Displaying Pointers
To display the value at memory address stored in the pointer, must dereference:
fmt.Printf("%d\n", *aPtr)
To display the memory address stored in the pointer in a hexadecimal notation, with the "0x" prefix, use %p
or %v
, they are equivalent for pointers:
fmt.Printf("%p\n", aPtr)
fmt.Printf("%v\n", aPtr) // same thing
This will print:
0xc000012080
For more details on the pointer, including the type of the data it points to, use:
fmt.Printf("%#v\n", aPtr)
This will print:
(*int)(0xc000012080)
Pointers can be also represented using the "%X"
format specifier, which displays the pointer in base 16, upper case characters, without the "0x" prefix:
fmt.Printf("%X\n", aPtr)
This will print:
C000094018
Pointer Variable Name
Do we use someNamePtr
or someName
?
Also see:
Pointer Operators
The pointer data type comes with two operators: &
(the referencing operator), and *
(the dereferencing operator).
The Referencing Operator &
The referencing operator (the ampersand operator) returns an address, also known as a "reference", from a variable. &
should be read as "address of ...". It works with variables and also with literals. The syntax &user{name:"Bill"}
where user
is a struct
is legal. The address is represented internally as an instance of type pointer
. The address points to the location in memory where the instance associated with the "referenced" variable is stored.
&<variable-name>
color := "blue"
pointerToColor := &color
println(pointerToColor) // prints "0xc000058720"
The Dereferencing Operator *
The dereferencing operator (star operator) takes a pointer and returns the value in memory the pointer's address points toward. The variable must contain a pointer type instance, otherwise the code will not compile. The value thus exposed can be read or written.
*<pointer-name>
color := "blue"
pointerToColor := &color
println(*pointerToColor) // prints "blue"
*pointerToColor = "red"
println(color) // prints "red"