Go struct

结构

Go 中的struct与 C 中的 struct非常相似,并且 Go 没有 class 。使用 type<Name> struct{}定义结构,名称遵循可见性规则。

  • 支持指向自身的指针类型成员
  • 支持匿名结构,可用作成员或定义成员变量
  • 匿名结构也可以用于map的值
  • 可以使用字面值对结构进行初始化
  • 运行直接通过指针来读写结构成员
  • 相同类型的成员可进行直接拷贝赋值
  • 支持==!=比较运算符,但是不支持><
  • 支持匿名字段,本质上是定于了以某个类型名为名称的字段
  • 嵌入结构作为匿名字段看起来像继承,但不是继承
  • 可使用匿名字段指针
1
2
3
4
5
6
7
8
9
10
type person struct {
name string
age int
mobile int
}

func main() {
amy := person{"Amy", 18, 112340259}
fmt.Println(amy)
}

输出

1
{Amy 18 112340259}

操作

类似像JavaScript中对象属性的操作

1
2
3
4
5
func main() {
amy := person{"Amy", 18, 112340259}
+ amy.age = 22
fmt.Println(amy)
}

输出

1
{Amy 22 112340259}

值拷贝

作为函数的参数时,是一个值拷贝,而不是引用类型

1
2
3
4
5
6
7
8
9
10
11
12
func structTest1(a person) {
a.age = 30
fmt.Println("struct test 1", a)
}

func main() {
amy := person{"Amy", 18, 112340259}
amy.age = 22
fmt.Println(amy)
structTest1(amy)
fmt.Println("after:", amy)
}

输出

1
2
3
{Amy 22 112340259}
struct test 1 {Amy 30 112340259}
after: {Amy 22 112340259}

可以发现age在函数执行后并没有发生改变。如果需要改变,需要传递指针(地址)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
+ func structTest1(a *person) {
- func structTest1(a person) {
a.age = 30
fmt.Println("struct test 1", a)
}

func main() {
amy := person{"Amy", 18, 112340259}
amy.age = 22
fmt.Println(amy)
- structTest1(amy)
+ structTest1(&amy)
fmt.Println("after:", amy)
}

输出

1
2
3
{Amy 22 112340259}
struct test 1 &{Amy 30 112340259}
after: {Amy 30 112340259}

指向结构的指针

在初始化时,变成结构的指针,也可以达到上面的效果。

1
2
3
4
5
6
7
- amy := person{"Amy", 18, 112340259}
+ amy := &person{"Amy", 18, 112340259}

... 省略代码

+ structTest1(amy)
- structTest1(&amy)

在对一个结构进行初始化时,习惯性使用取地址符号&,变量就变成指向某个结构的指针,方便在下面编码过程中特地去获取地址。且也可以直接对结构中的属性直接进行操作

匿名结构

没定义结构的名称,临时声明了一个结构,并对字面值进行了初始化

1
2
3
4
5
6
7
8
dog := &struct {
color string
tail string
}{
"white",
"long",
}
fmt.Println(dog)

输出

1
&{white long}

结构体中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
type person struct {
name string
age int
mobile struct {
phone, address string
}
}

func main() {
a := &person{name: "amy", age: 18}
a.mobile.phone = "123"
a.mobile.address = "china"
fmt.Println(a)
}

输出

1
&{amy 18 {123 china}}

匿名字段

在结构体中未声明属性名

1
2
3
4
5
6
7
8
9
type pet struct {
string
int
}

func main() {
a := &pet{"dog", 2}
fmt.Println(a)
}

输出

1
&{dog 2}

如果此时交换初始化参数的位置,会发生错误

1
2
- a := &pet{"dog", 2}
+ a := &pet{2, "dog"}

输出

1
2
3
# command-line-arguments
.....: cannot use 2 (type untyped int) as type string in field value
.....: cannot use "dog" (type untyped string) as type int in field value

类型比较操作

同类型之间的可以进行比较,作==!=,不能作>或者<

1
2
3
a := pet{name: "Amy", age: 18}
b := pet{name: "Amy", age: 18}
fmt.Println(a == b)

输出

1
true

如果内容一致,但是类型不一样

1
2
3
a := pet{name: "Amy", age: 18}
b := dog{name: "Amy", age: 18}
fmt.Println(a == b)

输出

1
2
# command-line-arguments
.....: invalid operation: a == b (mismatched types pet and dog)

嵌入struct

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
type human struct {
name string
age int
sex int
}
type teacher struct {
human
class string
}
type student struct {
human
classRoom string
}

func main() {
a := teacher{human: human{"A", 12, 1}, class: "english"}
b := student{human{"a", 2, 0}, "2002"}
b.name = "aa"
fmt.Println(a, b)
}

输出

1
{{A 12 1} english} {{aa 2 0} 2002}

练习

如果匿名字段和外层结构有同名字段,应该如何进行操作

1
2
3
4
5
6
7
8
9
10
11
12
13
type basePo struct {
id string
}

type bizBasePo struct {
basePo
id string
}

func main() {
bill := bizBasePo{id: "1", basePo: basePo{id: "2"}}
fmt.Println(bill.id, bill.basePo.id)
}

输出

1
1 2

bizBasePobasePo存在同名字段

1
2
3
bill := bizBasePo{id: "1", basePo: basePo{id: "2"}}
+ bill.name = "3"
fmt.Println(bill.id, bill.basePo.id)

输出

1
3 2

如果直接改成这样

1
2
3
4
5
6
7
8
type basePo struct {
id string
}

type bizBasePo struct {
basePo
- id string
}

输出

1
2 2

如果是多个同名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
type basePo struct {
id string
}

+ type flowPo struct {
+ id string
+ }

type bizBasePo struct {
basePo
+ flowPo
}

func main() {
+ bill := bizBasePo{basePo: basePo{id: "2"}, flowPo: flowPo{id: "5"}}
fmt.Println(bill.id, bill.basePo.id)
}

输出

1
2
# command-line-arguments
...: ambiguous selector bill.id

编译错误,此时使用那个嵌入体中的字段

可以改成这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
type basePo struct {
id string
}

type flowPo struct {
basePo
id string
}

type bizBasePo struct {
flowPo
}

func main() {
bill := bizBasePo{flowPo: flowPo{id: "5", basePo: basePo{id: "2"}}}
fmt.Println(bill.id, bill.flowPo.id, bill.flowPo.basePo.id)
}
- the End -
0%