1. Pointers and their operations

A pointer is also a variable, and its value is the address of the variable, that is, the pointer points to the memory address of the variable. Pointers are associated with the address of a variable, so you can change the value of a variable through Pointers,

The manipulation of Pointers in GO is relatively simple, with just two operations to remember: & and *.

Take the address

Use & to precede a variable to “fetch the address”.

a := 10
b := &a
Copy the code

The values

* is used to evaluate the address to which the pointer points.

a := 10
b := &a
c := *b
Copy the code

When the function takes a pointer, manipulating the pointer directly gets the value of the type to which the pointer points:

func testfFunc(param *test)  {
   ifparam ! =nil {
      fmt.Println(param.value)
   }
}
Copy the code

2. Pointers vs. values

First, let’s write a method that mimics the append method:

value

We first declare a named type to bind the method, and then make the receiver of the method the value of that type.

Here the receiver receives a copy of the value, and the caller’s value does not change after modification.

type ByteSlice []int

func (slice ByteSlice) Append(data []byte) []byte {
   // The method body
}
Copy the code

In this way, we still need the method to return the updated slice.

Pointer to the

We can redefine the method to include a pointer to ByteSlice as the receiver of the method, so that the method overrides the slice provided by the caller and returns no value.

Here the receiver receives a reference, and after modification, the value of the caller changes.

func (p *ByteSlice) Append(data []byte) {
    slice := *p
    // The body is the same as above, except that there is no return value
    *p = slice
}
Copy the code

We change the function to a method similar to standard Write as follows:

func (p *ByteSlice) Write(data []byte) (n int, err error) {
    slice := *p
    / / same as above.
    *p = slice
    return len(data), nil
}
Copy the code

The type *ByteSlice satisfies the standard IO.Writer interface.

We pass in the address of ByteSlice because only *ByteSlice will satisfy io.writer. The difference between having a pointer or a value receiver is that a value method can be called through a pointer and a value, whereas a pointer method can only be called through a pointer.

“The reason for this rule is that pointer methods can modify receivers; Calling them by value causes the method to receive a copy of that value, so any changes are discarded, so the language does not allow this error. There is a convenient exception: if the value is addressable, the language automatically inserts an address operator to deal with generic pointer methods called by value. In our case, the variable B is addressable, so we simply call its Write method with b.write, and the compiler overwrites it as (&b).write.” From Effective Go

conclusion

As mentioned above, value methods can be called with Pointers and values, whereas pointer methods can only be called with Pointers. The exception in the latter sentence is that if the value is addressable, the pointer method can be called for that value.

This also solved a knot in my heart when I first learned to Go:

var command1 command   // Create an object of type object type
command2 := command{CommandNo: 1, CommandName: a}  // Object type
command3 := new(command)    // Pointer type
Copy the code

For both object and pointer types, the following methods can be called :(the recipient of this method is a pointer type)

func (command *command) excute(a) {
	
}

command1.excute()
command2.excute()
command3.excute()
Copy the code

Command1 and Command2 are both object types and by rights cannot call the excute() method. Being able to call means that the object value is addressable, and the compiler will rewrite it as (& Command).excute().

3. New and make

Both new and make are used for memory allocation.

In contrast, make is only used for initialization of slice, map, and channel, and the return value is a type.

New is used only for memory allocation of type, and the value of memory is type zero, and returns a pointer to memory.

new

When new allocates memory, it only sets the memory to zero and cannot be initialized.

p := new(SyncedBuffer)  // type *SyncedBuffer
var v SyncedBuffer      // type SyncedBuffer
Copy the code

New creates a variable of type pointer (address), and new(c) is equivalent to &c{}.

make

When make allocates memory for slices, maps, and channels, it returns an initialized (not zeroed) value of type T (not *T).

make([]int.10)  // Create a slice with length and capacity of 10
Copy the code