• Go语言 结构体


    Go语言

    9. 结构体

    在Go语言官网的常见问题解答一栏中,有这样一个问题:“Is Go an object-oriented language?(Go语言是否是一种面向对象语言?)”比较有意思的是,Go官方给出的回答是:“Yes and no.(既是也不是。)”

    Go语言中不支持类,但它提供了结构体,Go语言中的结构体和接口实现了面向对象编程的特性。

    9.1 理解结构体

    通过使用结构体,我们可以自定义一系列由相同类型或不同类型的数据构成的数据集合,用来实现较复杂的数据结构。

    结构体由一系列成员变量构成,这些成员变量对应着实体不同的属性。

    9.2 定义结构体

    GO语言中通过关键字type定义自定义类型,结构体定义需要使用type和struct关键字。

    type 结构体名 struct {
        成员变量1 类型1
        成员变量2 类型2
        成员变量3 类型3
        ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    【注意】

    • 结构体名:同一个包内结构体名不能重复。
    • 成员名:同一个结构体内,成员名不能重复。
    • 类型1、类型2……:表示结构体成员变量的类型。
    • 同类型的成员名可以写在同一行。
    • 当结构体、方法名或变量名的首字母为大写时(可被导出),就可以在当前包外进行访问。
    type Book struct {
        title,author string
        num,id int
    }
    
    • 1
    • 2
    • 3
    • 4

    9.3 实例化结构体

    一个结构体在定义完成后才能进行使用。结构体实例化时,会真正地分配内存。因此,必须在定义结构体并实例化后才能使用结构体的字段。

    三种方式:

    • 标准实例化
    • new函数实例化
    • 取地址实例化
    9.3.1 标准实例化

    结构体本身是一种自定义数据类型,和其他基本数据类型的声明格式类似,可以通过var关键字进行实例化。

    var 结构体实例 结构体类型
    
    • 1
    package main
    
    import "fmt"
    
    type Book struct {
       title  string
       author string
       num    int
       id     int
    }
    
    func main() {
       var book1 Book
       fmt.Println(book1)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

    【string和int类型变量的初始值为""和0】

    9.3.2 new函数实例化

    new函数可对结构体进行实例化,实例化完成后会返回结构体的指针类型。

    package main
    
    import "fmt"
    
    type Book struct {
       title  string
       author string
       num    int
       id     int
    }
    
    func main() {
       book1 := new(Book)
       fmt.Println(book1)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

    9.3.3 取地址实例化

    取地址实例化与使用new函数进行实例化类似,返回的是结构体指针类型。

    结构体实例 := &结构体类型{}
    
    • 1
    package main
    
    import "fmt"
    
    type Book struct {
       title  string
       author string
       num    int
       id     int
    }
    
    func main() {
       book1 := &Book{}
       fmt.Println(book1)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

    9.3.4 访问成员

    结构体实例化完成后,可通过“.”来访问结构体的成员变量,对成员变量进行赋值或修改。

    package main
    
    import "fmt"
    
    type Book struct {
       title  string
       author string
       num    int
       id     int
    }
    
    func main() {
       book1 := &Book{}
       book1.title = "Go语言"
       book1.author = "Tom"
       book1.num = 20
       book1.id = 152368
    
       fmt.Println("title:", book1.title)
       fmt.Println("author:", book1.author)
       fmt.Println("num", book1.num)
       fmt.Println("id", book1.id)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    9.4 初始化结构体

    Go语言中可以通过键值对格式和列表格式对结构体进行初始化。

    9.4.1 键值对格式初始化
    结构体实例 := 结构体类型{
        成员变量1:1,
        成员变量2:2,
        成员变量3:3,
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    package main
    
    import (
       "fmt"
    )
    
    type Book struct {
       title  string
       author string
       num    int
       id     int
    }
    
    func main() {
       book1 := &Book{
          title:  "Go语言",
          author: "Tom",
          num:    20,
          id:     152368,
       }
       fmt.Println("title:", book1.title)
       fmt.Println("author:", book1.author)
       fmt.Println("num", book1.num)
       fmt.Println("id", book1.id)
    }
    
    • 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

    在这里插入图片描述

    9.4.2 列表格式初始化
    结构体实例 := 结构体类型{1,2,3,
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    【注意】

    • 使用这种方式初始化结构体必须初始化所有的成员变量。
    • 值的填充顺序必须和结构体成员变量声明顺序保持一致。
    • 此方式与键值对的初始化方式不能混用。

    在这里插入图片描述

    9.5 结构体方法

    Go语言中,一个方法就是一个包含了接收者的函数。对于结构体方法,接收者可以是结构体类型的值或是指针。

    9.5.1 指针类型接受者

    当接收者类型为指针时,可以通过该方法改变该接收者的成员变量值,即使你使用了非指针类型实例调用该函数,也可以改变实例对应的成员变量值。

    package main
    
    import "fmt"
    
    type User struct {
       Name  string
       Email string
    }
    
    func (u *User) ChanegeName() { //指针类型接受者
       u.Name = "Tom"
    }
    
    func main() {
       u := &User{"Peter", "Go@go.com"}
       fmt.Println("Name:", u.Name, "Email:", u.Email)
       
       u.ChanegeName()
       fmt.Println("Name:", u.Name, "Email:", u.Email)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    即使实例不是指针类型,修改也能生效。

    在这里插入图片描述

    9.5.2 值类型接受者

    当接收者不是一个指针时,该方法操作对应接收者值的副本,否则即使你使用了指针调用函数,也无法改变成员变量值。

    func (u User) ChanegeName() { //值类型接受者
       u.Name = "Tom"
    }
    
    • 1
    • 2
    • 3

    9.6 结构体内嵌

    Go语言的结构体内嵌是一种组合特性,使用结构体内嵌可构建一种面向对象编程思想中的继承关系。结构体实例化后,可直接访问内嵌结构体的所有成员变量和方法。

    type 结构体名1 struct {
        成员变量1 类型1
        成员变量2 类型2
    }
    type 结构体名2 struct {
        结构体名1 
        成员变量3 类型3
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    9.6.1 初始化结构体内嵌

    结构体内嵌的初始化和结构体初始化类似,可以使用键值对或“.”的方式来进行初始化。

    package main
    
    import "fmt"
    
    type Book struct {
       title  string
       author string
       num    int
       id     int
    }
    
    type BookBorrow struct {
       Book
       borrowTime string
    }
    
    type BookNotBorrow struct {
       Book
       readTime string
    }
    
    func main() {
       bookBorrow := &BookBorrow{
          Book: Book{
             "Go语言",
             "Tom",
             20,
             152368,
          },
          borrowTime: "30",
       }
    
       fmt.Println(bookBorrow)
    
       bookNotBorrow := &BookNotBorrow{}
    
       bookNotBorrow.title = "Python"
       bookNotBorrow.author = "Peter"
       bookNotBorrow.num = 10
       bookNotBorrow.id = 152369
       bookNotBorrow.readTime = "50"
       fmt.Println(bookNotBorrow)
    }
    
    • 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

    在这里插入图片描述

    9.6.2 内嵌匿名结构体

    使用匿名结构体来代替普通的结构体,以使代码的编写更加便利。

    在定义匿名结构体时,无须type关键字,但是在初始化被嵌入的匿名结构体时,需要再次声明结构体才能赋予数据。

    package main
    
    import (
       "fmt"
    )
    
    type BookBorrow struct {
       Book struct { //内嵌匿名结构体
          title  string
          author string
          num    int
          id     int
       }
       borrowTime string
    }
    
    func main() {
       bookNotBorrow := &BookBorrow{
          Book: struct { //声明类型
             title  string
             author string
             num    int
             id     int
          }{
             "Go语言",
             "Tom",
             20,
             152368,
          },
          borrowTime: "30",
       }
       fmt.Println(bookNotBorrow)
    }
    
    • 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

    在这里插入图片描述

    9.7 匿名结构体

    9.7.1 匿名结构体定义与初始化

    匿名结构体,顾名思义,即没有名字的结构体,与匿名函数类似。匿名结构体无须type关键字就可以直接使用,匿名结构体在创建的同时也要创建对象。

    匿名结构体的初始化和使用更加简单,无须通过type关键字定义,且不用写出类型名称。

    title: Go语言
    结构体实例 := struct{
        //匿名结构体定义
        成员变量1 类型1
        成员变量2 类型2
        成员变量3 类型3
        ...
    }{
        //成员变量初始化(可选)
        成员变量1:1,
        成员变量2:2,
        成员变量3:3,
        ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    package main
    
    import "fmt"
    
    type Book struct {
       title  string
       author string
       num    int
       id     int
    }
    
    func main() {
       book1 := struct {
          title  string
          author string
          num    int
          id     int
       }{
          title:  "Go语言",
          author: "Tom",
          num:    20,
          id:     152368,
       }
       fmt.Println("title:", book1.title)
       fmt.Println("author:", book1.author)
       fmt.Println("num:", book1.num)
       fmt.Println("id:", book1.id)
    }
    
    • 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

    在这里插入图片描述

    9.7.2 匿名结构体的应用

    匿名结构体一般可用于组织全局变量、构建数据模板和解析JSON等。

    使用匿名结构体来临时存储经过解析后的JSON数据。

    package main
    
    import (
       "encoding/json"
       "fmt"
    )
    
    func main() {
       data := &struct {
          Code int
          Msg  string
       }{}
    
       jsonData := `{"code":200,"msg":""}`
       if err := json.Unmarshal([]byte(jsonData), data); err != nil {
          fmt.Println(err)
       }
       fmt.Println("code", data.Code)
       fmt.Println("msg:", data.Msg)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    9.9 知识拓展

    9.9.1 使用结构体解析XML文件

    XML即可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。

    在计算机中,标记指计算机所能理解的信息符号,通过此类标记,计算机之间可以处理包含各种信息的文章等。它可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。

    1998年,W3C就发布了XML 1.0规范,用来简化网络间的文档信息传输。

    XML本质上是一种树形的数据格式,我们可以定义与之匹配的Go语言的struct类型,然后通过xml包对XML文件中的数据进行解析,存储到自定义的结构体中。

    test.xml

    
    <Persons>
        <Person>
            <Name>小丁Name>
            <Age>22Age>
            <Interests>
                <Interest>看书Interest>
                <Interest>打游戏Interest>
            Interests>
        Person>
    
        <Person>
            <Name>凤凤Name>
            <Age>22Age>
            <Interests>
                <Interest>姜云升Interest>
                <Interest>吃零食Interest>
            Interests>
        Person>
    Persons>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    解析xml

    package main
    
    import (
       "encoding/xml"
       "fmt"
       "io/ioutil"
    )
    
    type Result struct {
       Person []Person
    }
    
    type Person struct {
       Name      string
       Age       string
       Interests Interests
    }
    
    type Interests struct {
       Interest []string
    }
    
    func main() {
       var res Result
       content, err := ioutil.ReadFile("第9章结构体/知识拓展/test.xml")
       if err != nil {
          fmt.Println(err)
          return
       }
       err = xml.Unmarshal(content, &res)
       if err != nil {
          fmt.Println(err)
       }
       fmt.Println("XML文件解析后内容为:")
       fmt.Println(res)
    }
    
    • 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

    在这里插入图片描述

    Go语言中是利用反射机制将来自XML文件中的数据反射成对应的struct对象的,其中缺少的元素或空属性值将被解析为零值。

  • 相关阅读:
    华为公司 java 面试题
    2013年12月1日 Go生态洞察:Go 1.2版本发布
    代码提交没有记录到github activity和contribute
    字节跳动岗位薪酬体系曝光,看完感叹:不服不行
    正则表达式
    C++初阶学习第七弹——探索STL奥秘(二)——string的模拟实现
    Android Hook View的创建流程
    SpringBoot集成WebSocket实现在线聊天
    ArcGIS地图投影与坐标系转换的方法
    FPGA片内RAM读写测试实验
  • 原文地址:https://blog.csdn.net/weixin_44226181/article/details/125900354