struct

struct(结构体)的定义

struct(结构体)是一种聚合类型,里面可以包含任何类型的值,这些值就是我们定义的结构的成员,也称为字段

关键字和声明

type+struct

1
2
3
4
type structName struct{
fieldName typeName
...
}

示例

1
2
3
4
type person struct{
name string
age uint
}

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
type person struct{
name string
age uint
// 结构体里面值的类型可以是自定义的类型
addr address
}

type address struct{
province string
city string
}

func main(){
user := person{name: "JunNanZeng",
age: 18,
addr: address{province: "浙江省",
city: "玉环市"}}
fmt.Println(user.name)
fmt.Println(user.addr.city)
}
  • 结构体里面值的类型可以为结构体
  • 给变量赋值结构体时内容可以为空,这样所有字段为空

由于golang没有python和c++那样的class用来定义类,所以在golang中,可以使用结构体完成面对对象

interface

interface(接口)的定义

interface(接口)是与调用方的一种约定,它是一个高度抽象的类型,不用与具体的实现细节绑定在一起。接口要做的是定义好约定,告诉调用方自己可以做什么,但调用方不用直到它内部的实现,这与我们见到的具体类型如int, map, slice等不一样。

关键字和声明

关键字type interfaceName interface

1
2
3
type Stringer interface {
String() string
}

告诉调用者使用String()方法获得一个字符串

接口实现

之前,我们不能直接打印出结构体的内容,现在我们可以定义我们结构体要输出的内容了。

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
type person struct{
name string
age uint

addr address
}
type address struct{
province string
city string
}

// 定义一个接口Stringer
type Stringer interface{
// 定义接口方法String
String() string
}

// 定义结构体person的方法String
func (p person) String() string{
return fmt.Sprintf("the name is %s, age is %d", p.name, p.age)
}

// 定义结构体address的方法String
func (addr address) String() string{
return fmt.Sprintf("the province is %s, city is %s", addr.province, addr.city)
}

// 传入一个参数,调用接口Stringer
func PrintString(s Stringer){
// 接口Stringer调用结构体的String方法
fmt.Println(s.String())
}

func main(){
user := person{
name: "JunNanZeng",
age: 18,
addr: address{
province: "浙江省",
city: "玉环市"}}
PrintString(user)
// the name is JunNanZeng,age is 18
PrintString(user.addr)
// the province is 浙江省,city is 玉环市
}

个人理解

接口其实就是一个中转站,这里放着可以调用的方法,然后结构体,类等要实现对应的方法,否则无法编译通过。

只要接口的约定不变,接口的实现者可以更好地升级重构。

值和指针类型接收者

在实现方法的时候,不仅结构体的值类型接收者会实现接口,结构体的指针类型接收者也会实现接口

1
2
3
4
5
6
7
func main(){
p := &user
PrintString(user)
// the name is JunNanZeng,age is 18
PrintString(p)
// the name is JunNanZeng,age is 18
}

将person方法string中值接收者改成指针接收者

1
2
3
4
5
6
// 修改之前
// func (p person) string() string
// 修改之后
func (p *person) string() string {
return fmt.Sprintf("the name is %s, age is %d", p.name, p.age)
}

此时我们运行以下代码,将报错

1
2
3
func main(){
PrintString(user)
}

报错信息

1
2
can not use user (type person) as type Stringer in argument to PrintString:
person does not implement Stringer (String method has pointer receiver)

想要编译通过就要修改一下代码

1
2
3
4
func main(){
p := &user
PrintString(p)
}

报错的原因:

person方法string值接收者改成指针接收者,此时接口只实现指针的Stringer的接口,没有实现值的接口

值类型接收者和指针类型接收者的接口实现规则

方法接受者 实现接口的类型
(p person) person 和 *person
(p *person) *person