Go 向函数传递指针参数
Go 语言允许向函数传递指针,只需要在函数定义的参数上设置为指针类型即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 100
var b int = 200
fmt.Printf("交换前 a 的值 : %d\n", a)
fmt.Printf("交换前 b 的值 : %d\n", b)
/* 调用函数用于交换值
* &a 指向 a 变量的地址
* &b 指向 b 变量的地址
*/
swap(&a, &b)
fmt.Printf("交换后 a 的值 : %d\n", a)
fmt.Printf("交换后 b 的值 : %d\n", b)
}
func swap(x *int, y *int) {
var temp int
temp = *x /* 保存 x 地址的值 */
*x = *y /* 将 y 赋值给 x */
*y = temp /* 将 temp 赋值给 y */
}
输出结果:
交换前 a 的值 : 100
交换前 b 的值 : 200
交换后 a 的值 : 200
交换后 b 的值 : 100
自定义类型Struct
Go中的 struct:
1
2
3
4
5
6
7
8
9
10
11
12可将类型分为命名和未命名两大类。命名类型包括 bool、int、string 等,而 array、slice、map 等和具体元素类型、长度等有关,属于未命名类型。
具有相同声明的未命名类型被视为同一类型。
• 具有相同基类型的指针。
• 具有相同元素类型和长度的 array。
• 具有相同元素类型的 slice。
• 具有相同键值类型的 map。
• 具有相同元素类型和传送方向的 channel。
• 具有相同字段序列 (字段名、类型、标签、顺序) 的匿名 struct。
• 签名相同 (参数和返回值,不包括参数名称) 的 function。
• 方法集相同 ( 方法名、方法签名相同,和次序无关) 的 interface。struct 特点:
1
2
3
4
5
6
7
8
91. 用来自定义复杂数据结构
2. struct里面可以包含多个字段(属性)
3. struct类型可以定义方法,注意和函数的区分
4. struct类型是值类型
5. struct类型可以嵌套
6. Go语言没有class类型,只有struct类型
7. 结构体是用户单独定义的类型,不能和其他类型进行强制转换
8. golang中的struct没有构造函数,一般可以使用工厂模式来解决这个问题。
9. 我们可以为struct中的每个字段,写上一个tag。这个tag可以通过反射的机制获取到,最常用的场景就是json序列化和反序列化。
可以理解为面向对象编程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49struct声明及初始化:
声明:
type typeName struct {
//...
}
eg:
package main
type global struct{}
func main() {
type local struct{}
}
初始化:
方法有几种:
package main
import (
"fmt"
)
type Test struct {
int
string
}
var a Test
func main() {
b := new(Test) //同 var b *Test = new(Test)
c := Test{1, "c"}
d := Test{}
e := &Test{}
f := &Test{2, "f"} //同 var d *Test = &Test{2, "f"}
fmt.Println(a, b, c, d, e, f)
// 注: a b c d 返回 Test 类型变量;e f 返回 *Test 类型变量;若无初始化值,则默认为零值
}
输出结果:
{0 } &{0 } {1 c} {0 } &{0 } &{2 f}初始化值可以分为两种
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24a. 有序: typeName{value1, value2, ...} 必须一一对应
b. 无序: typeName{field1:value1, field2:value2, ...} 可初始化部分值
栗子:
a:有序
type Person struct {
name string
age int
sex int
phone int
}
func main() {
person := Person{"lff", 23, 1, 18135479521}
fmt.Println(person)
}
b: 无序
func main() {
p2 := Person{age: 23} //无序,指你可以指定给p2赋哪个字段的值
fmt.Println(person)
}操作 struct
1
2
3
4
5声明的struct与普通类型一样
访问结构体中的一个变量名, 用 "." 来连接:
varName.field 或 (*varName).field
如操作上面 Person 结构体中的 age : p.age = 35
也可以作为函数中的参数,返回值类型1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45举个栗子:
package main
import "fmt"
//1. 声明一个自定义类型名为 Person 的结构体
type Person struct {
name string
age int
}
func main() {
//2. 初始化
var p1 Person
p2 := Person{}
p3 := Person{"James", 23}
p4 := Person{age: 23}
fmt.Println(p1, p2, p3, p4)
p5 := new(Person)
p6 := &Person{}
p7 := &Person{"James", 23}
p8 := &Person{age: 23}
fmt.Println(p5, p6, p7, p8)
//3. 操作
p1.age = 50
p2.age = 25
if compareAge(p1, p2) {
fmt.Println("p1 is older than p2")
} else {
fmt.Println("p2 is older than p1")
}
}
func compareAge(p1, p2 Person) bool {
if p1.age > p2.age {
return true
}
return false
}
输出:
{ 0} { 0} {James 23} { 23}
&{ 0} &{ 0} &{James 23} &{ 23}
p1 is older than p2匿名字段
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124匿名字段:
声明一个 struct1 可以包含已经存在的 struct2 或者go语言中内置类型作为内置字段,称为匿名字段,即只写了 typeName,无 varName,但是 typeName 不能重复。
匿名字段与面向对象程序语言中的继承
声明及初始化:
package main
import (
"fmt"
)
type Person struct {
name string
age int
addr string
}
type Employee struct {
Person //匿名字段
salary int
int //用内置类型作为匿名字段
addr string //类似于重载
}
func main() {
em1 := Employee{Person{"rain", 23, "qingyangqu"}, 5000, 100, "gaoxingqu"}
fmt.Println(em1)
// var em2 Person = em1
// Error: cannot use em1 (type Employee) as type Person in assignment (没有继承, 然也不会有多态)
var em2 Person = em1.Person // 同类型拷贝。
fmt.Println(em2)
}
输出结果:
{{Murphy 23 帝都} 5000 100 北京}
{Murphy 23 帝都}
操作
访问方式也是通过 "." 来连接
相同字段采用最外层优先访问,类似于重载
em1.addr 访问的是 Employee 中最外层的 addr
em1.Person.addr 访问的是 Employee 中 Person 中的 addr
package main
import "fmt"
type Person struct {
name string
age int
addr string
}
type Employee struct {
Person //匿名字段
salary int
int //用内置类型作为匿名字段
addr string //类似于重载
}
func main() {
/*
var em1 Employee = Employee{}
em1.Person = Person{"rain", 23, "帝都"}
em1.salary = 5000
em1.int = 100 //使用时注意其意义,此处无
em1.addr = "北京"
*/
//em1 := Employee{Person{"rain", 23, "帝都"}, 5000, 100, "北京"}
//初始化方式不一样,但是结果一样
em1 := Employee{Person: Person{"Murphy", 23, "帝都"}, salary: 5000, int: 100, addr: "北京"}
fmt.Println(em1)
fmt.Println("live addr(em1.addr) = ", em1.addr)
fmt.Println("work addr(em1.Person.addr) = ", em1.Person.addr)
em1.int = 200 //修改匿名字段的值
}
输出:
{{Murphy 23 帝都} 5000 100 北京}
live addr(em1.addr) = 北京
work addr(em1.Person.addr) = 帝都
空结构 "节省" 内存, 如用来实现 set 数据结构,或者实现没有 "状态" 只有方法的 "静态类"。
package main
func main() {
var null struct{}
set := make(map[string]struct{})
set["a"] = null
}
不能同时嵌入某一类型和其指针类型,因为它们名字相同。
package main
type Resource struct {
id int
}
type User struct {
*Resource
// Resource // Error: duplicate field Resource
name string
}
func main() {
u := User{
&Resource{1},
"Administrator",
}
println(u.id)
println(u.Resource.id)
}
输出结果:
1
1