0x1234CDEF
.
*T
, where T
can be an arbitrary type. Type T
is called the base type of pointer type *T
.
*T
, then the base type of the named pointer type is T
.
*int // An unnamed pointer type whose base type is int.
**int // An unnamed pointer type whose base type is *int.
// Ptr is a named pointer type whose base type is int.
type Ptr *int
// PP is a named pointer type whose base type is Ptr.
type PP *Ptr
nil
. No addresses are stored in nil pointer values.
T
can only store the addresses of values of type T
.
new
function can be used to allocate memory for a value of any type. new(T)
will allocate memory for a T
value (an anonymous variable) and return the address of the T
value. The allocated value is a zero value of type T
. The returned address is viewed as a pointer value of type *T
.
t
of type T
, we can use the expression &t
to take the address of t
, where &
is the operator to take value addresses. The type of &t
is viewed as *T
.
p
of a pointer type whose base type is T
, how can you get the value at the address stored in the pointer (a.k.a., the value being referenced by the pointer)? Just use the expression *p
, where *
is called dereference operator. *p
is called the dereference of pointer p
. Pointer dereference is the inverse process of address taking. The result of *p
is a value of type T
(the base type of the type of p
).
package main
import "fmt"
func main() {
p0 := new(int) // p0 points to a zero int value.
fmt.Println(p0) // (a hex address string)
fmt.Println(*p0) // 0
// x is a copy of the value at
// the address stored in p0.
x := *p0
// Both take the address of x.
// x, *p1 and *p2 represent the same value.
p1, p2 := &x, &x
fmt.Println(p1 == p2) // true
fmt.Println(p0 == p1) // false
p3 := &*p0 // <=> p3 := &(*p0) <=> p3 := p0
// Now, p3 and p0 store the same address.
fmt.Println(p0 == p3) // true
*p0, *p1 = 123, 789
fmt.Println(*p2, x, *p3) // 789 789 123
fmt.Printf("%T, %T \n", *p0, x) // int, int
fmt.Printf("%T, %T \n", p0, p1) // *int, *int
}
package main
import "fmt"
func double(x int) {
x += x
}
func main() {
var a = 3
double(a)
fmt.Println(a) // 3
}
double
function in the above example is expected to modify the input argument by doubling it. However, it fails. Why? Because all value assignments, including function argument passing, are value copying in Go. What the double
function modified is a copy (x
) of variable a
but not variable a
.
double
function is let it return the modification result. This solution doesn't always work for all scenarios. The following example shows another solution, by using a pointer parameter.
package main
import "fmt"
func double(x *int) {
*x += *x
x = nil // the line is just for explanation purpose
}
func main() {
var a = 3
double(&a)
fmt.Println(a) // 6
p := &a
double(p)
fmt.Println(a, p == nil) // 12 false
}
&a
and its copy x
used in the function body both reference the same value, so the modification on *x
is equivalent to a modification on *p
, a.k.a., variable a
. In other words, the modification in the double
function body can be reflected out of the function now.
double
function call, the local pointer p
doesn't get modified to nil
.
func newInt() *int {
a := 3
return &a
}
p
, p++
and p-2
are both illegal.
p
is a pointer to a numeric value, compilers will view *p++
is a legal statement and treat it as (*p)++
. In other words, the precedence of the pointer dereference operator *
is higher than the increment operator ++
and decrement operator --
.
package main
import "fmt"
func main() {
a := int64(5)
p := &a
// The following two lines don't compile.
/*
p++
p = (&a) + 8
*/
*p++
fmt.Println(*p, a) // 6 6
fmt.Println(p == &a) // true
*&a++
*&*&a++
**&p++
*&*p++
fmt.Println(*p, a) // 10 10
}
T1
can be directly and explicitly converted to another pointer type T2
only if either of the following two conditions is get satisfied.
T1
and T2
are identical (ignoring struct tags), in particular if either T1
and T2
is a unnamed type and their underlying types are identical (considering struct tags), then the conversion can be implicit. Struct types and values will be explained in the next article.
T1
and T2
are both unnamed pointer types and the underlying types of their base types are identical (ignoring struct tags).
type MyInt int64
type Ta *int64
type Tb *MyInt
*int64
can be implicitly converted to type Ta
, and vice versa, for their underlying types are both *int64
.
*MyInt
can be implicitly converted to type Tb
, and vice versa, for their underlying types are both *MyInt
.
*MyInt
can be explicitly converted to type *int64
, and vice versa, for they are both unnamed and the underlying types of their base types are both int64
.
Ta
can't be directly converted to type Tb
, even if explicitly. However, by the just listed first three facts, a value pa
of type Ta
can be indirectly converted to type Tb
by nesting three explicit conversions, Tb((*MyInt)((*int64)(pa)))
.
*uint64
, in any safe ways.
==
and !=
operators. Two Go pointer values can only be compared if either of the following three conditions are satisfied.
nil
identifier.
package main
func main() {
type MyInt int64
type Ta *int64
type Tb *MyInt
// 4 nil pointers of different types.
var pa0 Ta
var pa1 *int64
var pb0 Tb
var pb1 *MyInt
// The following 6 lines all compile okay.
// The comparison results are all true.
_ = pa0 == pa1
_ = pb0 == pb1
_ = pa0 == nil
_ = pa1 == nil
_ = pb0 == nil
_ = pb1 == nil
// None of the following 3 lines compile ok.
/*
_ = pa0 == pb0
_ = pa1 == pb1
_ = pa0 == Tb(nil)
*/
}
unsafe.Pointer
type) provided by the unsafe
standard package can be used to break the restrictions made for pointers in Go. The unsafe.Pointer
type is like the void*
in C. In general the unsafe ways are not recommended to use.
The Go 101 project is hosted on Github. Welcome to improve Go 101 articles by submitting corrections for all kinds of mistakes, such as typos, grammar errors, wording inaccuracies, description flaws, code bugs and broken links.
If you would like to learn some Go details and facts every serveral days, please follow Go 101's official Twitter account @zigo_101.
reflect
standard package.sync
standard package.sync/atomic
standard package.