Structure and method
1. Values, pointers and references
We now have a program:
package main
import "fmt"
func main() {
// a,b 是一个值
a := 5
b := 6
fmt.Println("a的值:", a)
// 指针变量 c 存储的是变量 a 的内存地址
c := &a
fmt.Println("a的内存地址:", c)
// 指针变量不允许直接赋值,需要使用 * 获取引用
//c = 4
// 将指针变量 c 指向的内存里面的值设置为4
*c = 4
fmt.Println("a的值:", a)
// 指针变量 c 现在存储的是变量 b 的内存地址
c = &b
fmt.Println("b的内存地址:", c)
// 将指针变量 c 指向的内存里面的值设置为4
*c = 8
fmt.Println("a的值:", a)
fmt.Println("b的值:", b)
// 把指针变量 c 赋予 c1, c1 是一个引用变量,存的只是指针地址,他们两个现在是独立的了
c1 := c
fmt.Println("c的内存地址:", c)
fmt.Println("c1的内存地址:", c1)
// 将指针变量 c 指向的内存里面的值设置为4
*c = 9
fmt.Println("c指向的内存地址的值", *c)
fmt.Println("c1指向的内存地址的值", *c1)
// 指针变量 c 现在存储的是变量 a 的内存地址,但 c1 还是不变
c = &a
fmt.Println("c的内存地址:", c)
fmt.Println("c1的内存地址:", c1)
}
print out:
a的值: 5
a的内存地址: 0xc000016070
a的值: 4
b的内存地址: 0xc000016078
a的值: 4
b的值: 8
c的内存地址: 0xc000016078
c1的内存地址: 0xc000016078
c指向的内存地址的值 9
c1指向的内存地址的值 9
c的内存地址: 0xc000016070
c1的内存地址: 0xc000016078
So a,b
is the value of a variable, but c
a pointer variable, c1
is a reference variable.
If it is &
added before the variable a
:, c := &a
it means that a
the memory address of the variable is c
pointed to a
, it is a pointer variable.
When getting or setting the value of the memory pointed to by the pointer, add in front of the pointer variable *
and then assign the value, such as:, *c = 4
the variable pointed to by the pointer a
will change.
If the pointer variable is assigned to another variable:, c1 := c
then the other variable c1
can be called a reference variable, the value it stores is also the memory address, and the memory address points to the variable a
. At this time, the reference variable is just a copy of the pointer variable, the two variables are mutually independent.
Value variables can be called value types, and reference variables and pointer variables can be called reference types.
How to declare a variable of reference type (that is, a pointer variable)?
We can add one before the data type *
to indicate:
var d *int
We will only distinguish between variables by value type and reference type in the future.
2. Structure
With the basic data types, it is not enough, so Golang
support us to define our own data types, structures:
// 结构体
type Diy struct {
A int64 // 大写导出成员
b float64 // 小写不可以导出
}
The name of the structure is Diy
used type 结构体名字 struct
to define.
There are some members A
and in the structure b
, just like the variable definition, the type int64
and are float64
placed at the back, there is no need to separate any symbols, only need to wrap. The lower-case members in the structure cannot be used outside the package, that is, they cannot be exported.
When using a structure:
// 新建结构体,值
g := diy.Diy{
A: 2,
//b: 4.0, // 小写成员不能导出
}
// 新建结构体,引用
k := &diy.Diy{
A: 2,
}
// 新建结构体,引用
m := new(diy.Diy)
m.A = 2
You can use the structure according to the basic data type, created above:
g := diy.Diy{
A: 2,
//b: 4.0, // 小写成员不能导出
}
Is a value type structure.
You can also use the structure value in front of one &
or use new
to create a reference type structure, such as:
// 新建结构体,引用
k := &diy.Diy{
A: 2,
}
// 新建结构体,引用
m := new(diy.Diy)
m.A = 2
What is the difference between reference and value type structures?
We know that the variables inside and outside the function are independent. When the parameter is passed into the function, the parameter is a copy of the value. The variable in the function is constrained in the function body. Even if the value of the variable passed in the function is modified, the outside of the function I couldn't find it.
But the variable of the reference type is passed by value when it is passed into the function, but the memory address of the reference type is copied. It can be said that a reference is copied. This reference points to a structure outside the function. Use this reference in the function Modify the value of the structure inside, the outside function will also be found.
If the incoming structure is not a reference type structure, but a value type structure, then a complete copy of the structure will be made, and the structure is not related to the original structure.
The built-in data type slices slice
and dictionaries map
are reference types and do not require any additional operations, so passing these two types as function parameters is more dangerous, and you need to be cautious when developing.
Three, methods
A structure can be bound to a function, which means that this function can only be used by the structure. This function is called a structure method:
// 引用结构体的方法,引用传递,会改变原有结构体的值
func (diy *Diy) Set(a int64, b float64) {
diy.A = a
diy.b = b
return
}
// 值结构体的方法,值传递,不会改变原有结构体的值
func (diy Diy) Set2(a int64, b float64) {
diy.A = a
diy.b = b
return
}
It's just that on the basis of the previous function func Set(a int64, b float64)
, it becomes func (diy *Diy) Set(a int64, b float64)
, but in the function, you can use diy
the members in the structure variable .
The structure of the value type above diy Diy
can use the Set2
method, and the structure of the reference type diy *Diy
can use the Set
method.
If this is the case, every time we use a structure method, we must pay attention to whether the structure is a value or a reference type. Fortunately, we have Golang
broken our hearts. Each time a method is called using a structure, the structure will be automatically converted To adapt the method. For example, the following:
// 新建结构体,值
g := diy.Diy{
A: 2,
//b: 4.0, // 小写成员不能导出
}
g.Set(1, 1)
fmt.Printf("type:%T:%v\n", g, g) // 结构体值变化
g.Set2(3, 3)
fmt.Printf("type:%T:%v\n", g, g) // 结构体值未变化
// 新建结构体,引用
k := &diy.Diy{
A: 2,
}
k.Set(1, 1)
fmt.Printf("type:%T:%v\n", k, k) // 结构体值变化
k.Set2(3, 3)
fmt.Printf("type:%T:%v\n", k, k) // 结构体值未变化
The structure is g
a value type, you can't call the Set
method originally , but with the Golang
help of conversion, we have no sense, and then the value type becomes a reference type. Similarly, it k
is a reference type, and the Set2
method can still be used .
Earlier we also said that a function is passed in a reference, and the value corresponding to the reference is modified in the function, which will also be found outside the function.
The structure method is also the same, but the structure itself is diffused in the range, and the structure itself can be modified in the method, but if the structure is a value, then the outside world cannot be found after the modification.
Third, the keywords new and make
The keyword is new
mainly used to create a reference type structure, only the structure can be used.
Keywords make
are used to create and initialize a slice or dictionary. We can assign directly to use:
e := []int64{1, 2, 3} // slice
f := map[string]int64{"a": 3, "b": 4} // map
But this direct assignment is relatively crude, because we may not know where and how much data there is when we use it.
Therefore, when we create slices and dictionaries, we can specify the size of the capacity. See example:
s := make([]int64, 5)
s1 := make([]int64, 0, 5)
m1 := make(map[string]int64, 5)
m2 := make(map[string]int64)
fmt.Printf("%#v,cap:%#v,len:%#v\n", s, cap(s), len(s))
fmt.Printf("%#v,cap:%#v,len:%#v\n", s1, cap(s1), len(s1))
fmt.Printf("%#v,len:%#v\n", m1, len(m1))
fmt.Printf("%#v,len:%#v\n", m2, len(m2))
After running:
[]int64{0, 0, 0, 0, 0},cap:5,len:5
[]int64{},cap:5,len:0
map[string]int64{},len:0
map[string]int64{},len:0
Slicing can be used make([],占用容量大小,全部容量大小)
to define, you can create a slice of capacity size 5
, but the actual occupied capacity is 0
, for example make([]int64, 0, 5)
, you reserve 5
a space, so that when you slice append
, you will not allocate space internally because of insufficient capacity, saving time.
If you omit the following parameters such as make([]int64, 5)
, then it is equal make([]int64, 5,5)
, because then the total capacity is equal to the occupied capacity. Built-in language cap
and len
can view the full capacity size, the occupied capacity size.
Similarly, the dictionary can also specify the capacity and use it make([],容量大小)
, but it does not have the so-called occupied capacity. It removes this feature because we use slices, which may require five blank initial values, but if the dictionary has no keys, reserve the initial The value has no effect. Omitting the size of the capacity means creating a 0
key-value structure with a capacity of 0. When assigning a value, it will automatically allocate space.
Fourth, the difference between built-in syntax and functions, methods
Functions are an encapsulation of code fragments by binding functions and structures.
But Golang
there are some built-in grammar, is not a function, not a method, such as append
, , cap
, len
, make
this is a grammatical features.
The grammatical features are provided by high-level languages, which help you hide details such as how to allocate memory.
Series article entry
I am the star Chen, Welcome I have personally written data structures and algorithms (Golang achieve) , starting in the article to read more friendly GitBook .
- Data structure and algorithm (Golang implementation) (1) A simple introduction to Golang-Preface
- Data structures and algorithms (Golang implementation) (2) A simple introduction to Golang-packages, variables and functions
- Data structure and algorithm (Golang implementation) (3) A simple introduction to Golang-flow control statement
- Data structures and algorithms (Golang implementation) (4) A simple introduction to Golang-structures and methods
- Data structure and algorithm (Golang implementation) (5) A simple introduction to Golang-interface
- Data structure and algorithm (Golang implementation) (6) A simple introduction to Golang-concurrency, coroutines and channels
- Data structure and algorithm (Golang implementation) (7) A simple introduction to Golang-standard library
- Data Structure and Algorithm (Golang Implementation) (8.1) Basic Knowledge-Preface
- Data Structure and Algorithm (Golang Implementation) (8.2) Basic Knowledge-Divide and Conquer and Recursion
- Data structure and algorithm (Golang implementation) (9) Basic knowledge-algorithm complexity and progressive symbol
- Data structure and algorithm (Golang implementation) (10) Basic knowledge-the main method of algorithm complexity
- Data Structures and Algorithms (Golang Implementation) (11) Common Data Structures-Preface
- Data structures and algorithms (Golang implementation) (12) Common data structures-linked lists
- Data structures and algorithms (Golang implementation) (13) Common data structures-variable-length arrays
- Data structures and algorithms (Golang implementation) (14) Common data structures-stack and queue
- Data Structures and Algorithms (Golang Implementation) (15) Common Data Structures-List
- Data Structures and Algorithms (Golang Implementation) (16) Common Data Structures-Dictionary
- Data structures and algorithms (Golang implementation) (17) Common data structures-trees
- Data Structure and Algorithm (Golang Implementation) (18) Sorting Algorithm-Preface
- Data structure and algorithm (Golang implementation) (19) Sorting algorithm-bubble sorting
- Data structure and algorithm (Golang implementation) (20) Sorting algorithm-selection sorting
- Data structure and algorithm (Golang implementation) (21) Sorting algorithm-insertion sort
- Data structure and algorithm (Golang implementation) (22) Sorting algorithm-Hill sorting
- Data structure and algorithm (Golang implementation) (23) Sorting algorithm-merge sorting
- Data structure and algorithm (Golang implementation) (24) Sorting algorithm-priority queue and heap sorting
- Data structure and algorithm (Golang implementation) (25) Sorting algorithm-quick sorting
- Data Structure and Algorithm (Golang Implementation) (26) Lookup Algorithm-Hash Table
- Data structure and algorithm (Golang implementation) (27) Search algorithm-binary search tree
- Data structure and algorithm (Golang implementation) (28) Search algorithm-AVL tree
- Data structure and algorithm (Golang implementation) (29) Finding algorithm-2-3 tree and left-leaning red-black tree
- Data structure and algorithm (implemented by Golang) (30) Finding algorithm-2-3-4 tree and ordinary red-black tree