go学习笔记(14)struct

IMG_6004.jpg

如果我们要把一组数据组合在一起就需要用到struct了,go语言中结构体有些类似于其他语言中的class,但又很不一样,go语言不支持继承,go语言通过组合来实现类似于继承的效果。

结构体的声明定义使用

可以这样定义一个struct

1
2
3
4
type Point struct {
X int
Y int
}

一旦定义好了结构体,我们就可以声明使用这个结构体的变量了。

1
2
3
4
var a Point
b := Point{1, 2}
fmt.Println(a)
fmt.Println(b)

输出:

1
2
{0 0}
{1 2}

在通过结构体字面量声明结构体时,必须把结构体中所有的字段都填好。如果想留空部分字段置为零值只填写需要的字段,则可以对这些字段单独进行定义。

1
2
3
// 只对X字段赋值,Y字段默认置为零值
c:=Point{X: 10}
fmt.Println(c)

输出:

1
{10 0}

结构体中的字段可以用.来访问

1
2
3
4
var d Point
d.X = 20
d.Y = 40
fmt.Println(d)

输出:

1
2
{10 0}
{20 40}

匿名结构体

在声明一个结构体变量时,可以直接定义这个结构体具有的字段,这样的结构体没有用type声明类型,特别适合只需要用一次结构体的场景。

1
2
3
4
5
6
7
8
9
10
11
12
var rect struct{
width int
height int
}
rect.width=10
rect.height=20
fmt.Println(rect)

circle:= struct {
radius int
}{5}
fmt.Println(circle)

输出:

1
2
{10 20}
{5}

最常见的匿名结构体的使用场景是进行外部数据转换,比如把json数据转换成go语言的结构体。另一个常见的使用场景是在写单元测试时通过结构体构造测试数据。

把外部的json数据转换成结构体:

1
2
3
4
5
6
7
8
9
pointData := `{"x":10,"y":20}`
// 结构体中的 `json:"x"`是结构体标签,
// 它定义了json与go结构体之间字段的映射关系
var p struct {
X int `json:"x"`
Y int `json:"y"`
}
json.Unmarshal([]byte(pointData), &p)
fmt.Println(p)

输出:

1
{10 20}

结构体的相等比较及类型转换

不同类型的结构体不能直接比较是否相等,要先转换成同类型结构体,结构体能不能比较取决于结构体中的字段是不是能比较的,如果结构体中的字段都是可比较的字段则它就能进行比较,如果结构体中的字段有切片、map、函数、channel等不可比较的字段时,就不能比较了。

go语言不支持字段不同的结构体之间的转换,但支持两个字段完全一样的结构体之间进行转换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
type girl1 struct {
name string
height float64
}
type girl2 struct {
name string
height float64
}

g1 := girl1{"wcy", 1.7}
g2 := girl2{"xmy", 1.6}
fmt.Println("g2:", g2)
g2 = girl2(g1)
fmt.Println("g2:", g2)

输出:

1
2
g2: {xmy 1.6}
g2: {wcy 1.7}

可以看到g1g2虽然是不同类型的结构体,但是它们可以进行类型转换。

如果两个结构体字段不完全相同就不能进行类型转换了:
8f56f451e01b2b175691936d09e75520.png

两个能比较的结构体中如果有一个是匿名结构体,只要结构体的字段完全一致就可以进行比较,无需进行类型转换。

1
2
3
4
5
6
7
8
9
10
11
12
type girl2 struct {
name string
height float64
}
g2 := girl2{"xmy", 1.6}
g4 := struct {
name string
height float64
}{"llj", 1.6}
fmt.Println(g4 == g2)
g4.name = "xmy"
fmt.Println(g4 == g2)

输出:

1
2
false
true

江达小记