【Go】结构体,方法,接口

结构体

  • Go语言是静态类型的语言,编译器需要在编译的时候知道每一个值的类型
  • 提前知道值的类型,可以合理的保存。有助于减少内存异常和Bug。
  • 一般需要知道:分配多少内存给这个值,这段内存表示什么。

定义与声明

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
package main

import "fmt"

func main() {

//结构体声明1和使用
var u user
fmt.Println(u) // {0}

//结构体声明2和使用
lisa := user{
name: "lisa",
email: "12@qq.com",
ext: 0,
add: "beijing",
}
fmt.Println(lisa) // {lisa 12@qq.com 0 beijing}

//结构体声明3和使用
mutong := user{"mutong","123",9,"beijing"}
fmt.Println(mutong) // {mutong 123 9 beijing}

fred := admin{
user: user{
name: "lisa",
email: "12@qq.com",
ext: 0,
add: "beijing",
},
level: "0",
}
fmt.Println(fred) // {{lisa 12@qq.com 0 beijing} 0}
}

//结构体定义
type user struct {
name string
email string
ext int
add string
}
//结构体定义
type admin struct {
user user
level string
}

自定义类型

1
type Duration int64

这个Duration是真是存在的一个类型,和int64是两个独立的类型,不能互相赋值

类型别名

1
2
type rune = int32
type byte = uint8

类型别名,仅仅是存在于编码阶段,实际运行的时候还是原来的类型,提高可读性。

匿名结构体

1
2
3
4
5
6
7
8
9
10
11
12
13

func main() {

s := struct {
name string
email string
ext int
add string
}{
"mutong","mutong",1,"mutong",
}
fmt.Println(s)
}

一般就是临时使用,没有复用

指针类型结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func main() {
//new()方法会直接声明一个指针,赋值的时候需要根据*p 根据地址取值。
//但是Go语言有一个语法糖,可以直接使用p.name去赋值
var p = new(person)
p.name = "mutong"
p.email = "mutong"
p.ext = 123
p.add = "123"
fmt.Println(*p)
}


type person struct {
name string
email string
ext int
add string
}

构造函数

  • 结构体是指针类型的,但是如果指针类型比较复杂的话,值拷贝性能开销会比较大,所以构造函数返回值一般是结构体指针类型
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    func main(){
    s :=newStudent(i,"mutong")
    fmt.Println(s)

    }
    //构造函数
    func newStudent(id int,name string) *student{
    return &student{
    Id: id,
    Name: name,
    }
    }

序列化与反序列化

大写表示公开

小写表示私有

  • json.Marshal(c1) 序列化
  • json.Unmarshal(c1) 反序列化
    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
    package main

    import (
    "encoding/json"
    "fmt"
    )
    // 如果一个Go语言中定义的标识符是首字母大写的,那么就是对外可见的
    // 如果一个结构体中的字段名首字母是答大写的,那么该自负就是对外可见的
    func main() {

    c1 := Class{
    Title: "重点班",
    Student: make([]student,0,20),
    }

    for i:= 0 ; i < 10; i++ {
    s :=newStudent(i,"mutong")
    c1.Student = append(c1.Student,s)
    }
    data, err := json.Marshal(c1)
    if err != nil{
    fmt.Println(err)
    }else {
    fmt.Printf("%s\n",data)
    }

    //JSON反序列化:JSON格式的字符串-->结构体
    str := `{"Title":"101","Students":[{"ID":0,"Name":"stu00"},{"ID":1,"Name":"stu01"}]}`

    var c2 Class
    err = json.Unmarshal([]byte(str), &c2)
    if err != nil {
    fmt.Println(err)
    return
    }
    fmt.Printf("%#v\n", c2)
    }

    //构造函数
    func newStudent(id int,name string)student{
    return student{
    Id: id,
    Name: name,
    }
    }
    type student struct {
    Id int
    Name string
    }
    //结构体嵌套
    type Class struct {
    Title string
    Student []student
    }


    几个注意:

  • 空结构体是不占用空间的
  • 构造

方法

  • 方法能够给用户定义的类型增加新的行为,方法实际上也为函数,只不过,在声明的时候在关键字func 和 方法名之间添加了一个参数
  • 方法属于特定的类型,因为方法又一个接收者变量,只能有这个接收者变量才能调用。
  • 函数不属于任何类型,可以直接调用。
  • 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
    package main

    import "fmt"

    func main(){
    mutong := person{
    name: "mutong",
    age: 20,
    }
    mutong.notify()
    mutong.changeAge(3)
    fmt.Println(mutong)

    //输出:
    //Print person`s name :mutong
    //{mutong 3 }

    }

    //普通方法
    func (p person) notify(){
    fmt.Println("Print person`s name :" + p.name)
    }

    //想要修改一个类型里面的值。需要使用指针接收者的方法
    func (p *person) changeAge(age int){
    p.age = age
    }

接口

接口的定义

  • 定义了一个接口之后,一定会有一个函数用接口类型做参数。
  • 也一定又一个方法实现了接口里面的方法,方法的参数是一个用户自定义的类型。
    1
    2
    3
    4
    5
    type 接口类型 interface {
    方法1(参数列表 ) 返回值
    方法2(参数列表 ) 返回值
    ...
    }
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
package main

import "fmt"

func main(){
t := teacher{
name: "mutong",
email: "123@qq.com",
}
teacherSpeak(&t)
teacherEat(&t)
}

type person interface {
speak()
eat()
}
type teacher struct {
name string
email string
}

//也一定又一个方法实现了接口里面的方法,方法的参数是一个用户自定义的类型。
func (teacher *teacher)speak(){
fmt.Println(teacher.name,"正在说")
}
func (teacher *teacher)eat() {
fmt.Println(teacher.name,"正在吃")
}

//定义了一个接口之后,一定会有一个函数用接口类型做参数。
func teacherSpeak(p person){
p.speak()
}

func teacherEat(p person){
p.eat()
}


使用搜索:谷歌必应百度