A pointer is a variable that holds a memory address.

Every variable has a memory address (but not every value has a memory address), and we can access and update the value of the variable through Pointers.

The way a pointer is declared

There are several common ways to declare a pointer variable p

1. x := 1    // or var x int, where x is initialized to zero
   p := &x   // p is a pointer to a variable x of type int and holds the address of x
2. var p *int    // p is also a pointer variable, but p is 
      
        because p does not point to any variable
      
3. p := new(int)  // new returns a variable of type int*, so p is an int* variable,
                  // refers to an anonymous int variable, and *p is initialized to zero
Copy the code

Pointer variables can also be compared with each other to determine whether addresses are equal

1. var p, q *int
   fmt.Println(p == q) // The output is true because p and q are 
      
        values
      
2. var x, y int
   p := &x
   q := &y
   fmt.Println(p == q) // The output is false because x and y are initialized to zero and p and q refer to two different variables
3. p := new(int)
   q := new(int)
   fmt.Println(p == q) // The output is false, again p and q refer to two different anonymous variables
Copy the code

Access and update variables

Pointers make it easy to access and update variables

x := 1
p := &x // p is a pointer to int*
*p = 2 // Use * to access and update the variable x pointed to by p, where x is 2
Copy the code

A variable of normal or aggregate type can be addressed by &. The zero value of any pointer is nil. If the pointer points to a valid variable, the pointer p! = nil

var x int64
p := &x // We can use & to fetch the address of x

// Aggregation type
type User struct {
    Id string
}

p := &User{      // p is a pointer to an anonymous User
    Id : "test",
}
q := &p.Id       // q refers to the string variable Id of the User type
Copy the code

The use of Pointers in functions

Pointers can appear as variables in function arguments and return values

func f(u *Type) *Type{}Copy the code
  • In the Go language, function parameters of all value types are passedCopy the valueThis means that changes to parameters inside a function cannot change the value of the original variable, whereas reference types (slice, pointer, map, chan, and function) can change the original variable inside the function
  • If the parameters are structures, arrays, etc., and the tangent structure is large, the efficiency of parameter transfer can be improved by using Pointers
p := &User{
    Id : "test",
}
p = changeId(p)
fmt.Println(*p) *p = {test1}

func changeId(u *User) *User {
    u.Id = "test1"
    return u
}

c := sha256.Sum256([]byte("x"))
fmt.Println(c)    // Output is [45 113 22 66 183 38 176 68 1 98 124...
zero(&c)
fmt.Println(c)    // Output is [0 0 0 0 0...

func zero(ptr *[32]byte) {
    for i := range ptr {
        ptr[i] = 0}}Copy the code

Use of Pointers in object methods

In Java, there are classes defined by display. Each Class has its own methods. Objects can call these methods to achieve specific functions. Struct structures are defined in Go, and each structure can act as a receiver. A series of methods can be defined in the receiver. For example, we can define a getUserId method for User as follows:

func (u User) getUserId(a) string {
    return u.Id
}
Copy the code

If the User structure is too large, it is inefficient to pass parameters, so we can use Pointers instead:

func (u *User) getUserId(a) string {
    return u.Id
}
Copy the code

In real applications, it is generally agreed that if the User class has a pointer as a receiver method, then all User methods must have a pointer receiver, even those functions that do not need the pointer receiver.

In addition, to avoid ambiguity, a type name is not allowed in the receiver when declaring a method if it is itself a pointer, as in the following example:

type P *User
func (p *P) f(a) {} // The compiler reported an error because P itself is already a pointer type
Copy the code

It is worth mentioning that in Go, if u is a variable of type User and the method getUserId requires a sink of type *User, we can also call it directly with u.getUserId(). The compiler implicitly calls getUserId with &u. But this method is limited to the case where u is a variable, as follows:

u.getUserId()                    // The compiler passes because u is a variable
User{Id : "test"}.getUserId()    // The compiler reported an error because the compiler could not directly help us find the address of the constant
(&User{Id : "test"}).getUserId()    // Get the address of the constant manually
Copy the code