Learn Go: 14. Pointer type

Posted by kidd1270 on Thu, 14 Oct 2021 05:13:40 +0200

>>Original address

Learn what

  1. What is a pointer?

  2. What is a pointer type?

  3. How to use and create pointer type variables?

  4. How to get values from pointer variables?

  5. How do I pass pointers?

What is a pointer

What is a memory address first? The point of popularity is that the number of data storage locations on computer is just like our ID number.

The pointer is the so-called memory address. The memory address is stored in the pointer variable.

Illustration: the left half of the figure is a string data, and the right half is a pointer variable, which stores the address of the string data. The address in the figure is purely fictitious.

Pointer type

The pointer type is to add an asterisk before any type. The format is as follows:

*BaseType

BaseType represents any type.

Example:

  • *Int represents the pointer type of a variable of type int.

  • *String represents the pointer type of a variable of type string.

type People struct {

    Name string

    Age  int

}
  • *People represents the pointer type of a variable of type people.

How to create pointer variables

Now create a variable of * int pointer type. The format is as follows:

var p *int

p is a pointer type variable. The variable has not been initialized. Now initialize the variable.

var num int =  11

p = &num

Use the & sign to obtain the address of the variable num and assign it to the pointer variable p.

Output pointer variable information as follows:

fmt.Println(p)

// output

0xc00000a088

The description at the beginning of 0x is hexadecimal, which is the memory address of the variable num.

Null pointer

Null pointer means that the pointer variable has no assignment, and this spatiotemporal pointer variable is equal to nil.

var empty *int

fmt.Println(empty == nil) 

// output

true

nil is similar to null in other languages. In Go language, it can only be compared with pointer type and interface type, and can only assign values to pointer type variables and interface type variables.

Dereferencing Pointers

After declaring a pointer variable, what should I do if I want to get a value from the pointer variable? The value of the pointer is often called dereference. The format is as follows:

var num int =  11

var p *int

p = &num

// Value

fmt.Println(*p)

// output

11

*p means to take the value from the variable num pointed to by the pointer. When taking the value, add a * sign in front of the pointer variable.

If the pointer variable is a null pointer, the compiler will report an error when taking a value from it.

panic: runtime error: invalid memory address or nil pointer dereference

structural morphology

If the pointer variable is a structure pointer type, there is no need to add * in front of the pointer variable when obtaining the field in the structure or calling the method.

p := &People{

            Name: "Old seedling",

            Age:  18,

        }

fmt.Pringln(p)

fmt.Println(p.Name)

or

fmt.Println((*p).Name)

// output

&{Laomiao 18}

Old seedling

Summary:

  • The structure pointer does not output an address

  • You do not need to add when calling fields or methods of a structure*

method

stay Last article The concept of pointer receiver has been touched on in. Let's briefly explain this. Please take a look at it in detail Custom types and structures - Methods.

If you want to modify the field in the structure through the method, you can set the receiver to the pointer type.

// type/struct.go

// ...

func (p *People) SetName(name string) {

    p.Name = name

}

func main() {

    people := People{

        Name: "Old seedling",

    }

    people.SetName("Chic brother")

    fmt.Println(people.Name)

}

// output

Chic brother

The receiver p of the SetName method is the pointer type. The Name field is modified, and the data of the people variable is also changed.

Pointer passing

In Go language, most types are value passing, that is, when passing values through functions, modifications in functions cannot affect the outside. If you want to change, use the pointer type.

// pointer/function.go

// ...

func UpdateNum(num *int) {

    *num = 2

}

func main() {

    n := 1

    UpdateNum(&n)

    fmt.Println(n)

}

// output

2

The UpdateNum function accepts an * int pointer type. The formal parameter num pointer type points to the argument variable n. therefore, the modification of num affects the value of variable n.

Individual types in Go language are reference types themselves. You can modify the value inside the function without using a pointer to affect the outside.

1. map and channel

These two are reference types, and there is no need to use pointers when passing. The channel will be explained with examples in subsequent articles.

// pointer/map.go

// ...

func SetCountry(countries map[string]string) {

    countries["china"] = "China"

}

func main() {

    c := make(map[string]string)

    SetCountry(c)

    fmt.Println(c)

}

// output

map[china:China]

This code initializes a map type, and then modifies its value through the SetCountry function.

2. Slice

In understanding Built in set - Slicing After this article, you should understand that the underlying reference of the slice is an array. The reference of the underlying array will not be changed when the slice is passed, but the array reference will be changed after the slice is appended.

// pointer/slice.go

//...

func AppendAnimals(animals []string) {

    animals = append(animals, "tiger", "elephant")

}

func main() {

    input := []string{"monkey"}

    AppendAnimals(input)

    fmt.Println(input)

}

// output

[monkey]

The AppendAnimals function appends elements to the slice, but the value of the external variable input is not affected, because the underlying array will be copied and the reference will be changed after the append operation.

If you want to affect the input variable in the function, use the pointer to solve it.

// pointer/slice.go

//...

func AppendAnimalsPointer(animals *[]string) {

    *animals = append(*animals, "tiger", "elephant")

}

func main() {

    input := []string{"monkey"}

    AppendAnimalsPointer(&input)

    fmt.Println(input)

}

// output

[Monkey tiger elephant]

If only the contents of the slice are modified when passing the slice, that is, no elements are appended, the original slice data will be affected because the reference of the underlying array has not changed.

// pointer/slice.go

//...

func UpdateAnimals(animals []string) {

    for i := range animals {

        animals[i] = "rabbit"

    }

}

func main() {

    updateInput := []string{"tiger", "elephant"}

    UpdateAnimals(updateInput)

    fmt.Println(updateInput)

}

// output

[Rabbit rabbit]

The UpdateAnimals function modifies the slice content. Through the output, you can see that the updateInput variable data has changed.

summary

Pointers can save the cost of replication, but the impact of dereference and garbage collection should be considered at the same time, so don't use pointers as the first choice for performance optimization.

Topics: Go interface