美文网首页
第六章 结构体

第六章 结构体

作者: Benedict清水 | 来源:发表于2021-02-20 17:38 被阅读0次

    Go语言中结构体是带有成员的复合类型。结构体成员是由一系列成员变量构成,这些成员变量也被称为“字段”。字段有以下特性:

    • 字段拥自己的类型和值
    • 字段名必须唯一
    • 字段的类型也可以是结构体,甚至是字段所在结构体的类型

    6.1 定义结构体

    结构体的定义格式如下:

    type 类型名 struct {
        字段1 类型
        字段2 类型
        ...
    }
    
    • 类型名:标识自定义结构体的名称,在同一个包内不能重复。
    • struct{}:表示结构体类型,type 类型名 struct{}可以理解为将struct{}结构体定义为类型名的类型。
    • 字段1、字段2......:表示结构体字段名。结构体中的字段名必须唯一。

    示例如下:

    type Point struct{
        x int
        y int
    }
    

    6.2 实例化结构体——为结构体分配内存并初始化

    实例化就是根据结构体定义的格式创建一份与格式一致的内存区域,结构体实例与实例间的内存是完全独立的。

    6.2.1 基本的实例化形式

    结构体本身是一种类型,以var的方式声明结构体即可完成实例化。
    基本的实例化格式如下:

    var ins T
    
    • T为结构体类型。
    • ins为结构体的实例。
      示例如下:
    type Point struct{
        x int
        y int
    }
    var p Point
    p.x = 10
    p.y = 20
    

    使用“.”来访问结构体的成员变量,如p.x和p.y等。结构体成员变量的赋值方法与普通变量的一致。

    6.2.2 创建指针类型的结构体

    Go语言中,还可以使用new关键字对类型(包括结构体、整型、浮点数、字符串等)进行实例化,结构体在实例化后会形成指针类型的结构体。
    使用new的格式如下:
    ins := new(T)

    • T 为类型,可以是结构体、整型、字符串等
    • ins: T 类型被实例化后保存到ins变量中,ins的类型为*T,属于指针。

    Go 语言让我们可以像访问普通结构体一样使用“.”访问结构体指针的成员。
    下面的例子定义了一个玩家(Player)的结构,玩家拥有名字、生命值和魔法值,实例化玩家(Player)结构体后,可对成员进行赋值。

    type Player struct{
        Name string
        HealthPoint int
        MagicPoint int
    }
    tank := new(Player)
    tank.Name = "Canon"
    tank.HealTPoint = 300
    

    经过new实例化的结构体实例在成员赋值上与基本实例化的写法一致。

    6.2.3 取结构体的地址实例化

    在Go语言中,对结构体进行“&”取地址操作时,视为对该类型进行一次new的实例化操作。取地址格式如下:

    ins := &T{}
    
    • T 表示结构体类型。
    • ins 为结构体的实例,类型为*T,是指针类型。

    下面使用结构体定义一个命令行指令,指令中包含名称、变量关联和注释等。对Command进行指针地址的实例化,并完成赋值过程。代码如下:

    type Command struct{
        Name string
        Var *int
        Comment string
    }
    // 对结构体进行赋值
    var version int = 1
    cmd := &Command()
    cmd.Name = "version"
    cmd.Var = &version
    cmd,Comment = "show version"
    

    取地址实例化是最广泛的一种结构体实例化方式。

    6.3 初始化结构体的成员变量

    初始化有两种方式:一种是字段“键值对”形式,另一种是多个值的列表形式。

    6.3.1 使用“键值对”初始化结构体

    结构体实例化后字段的默认值是字段类型的默认值,数值为0,字符串为空字符串,布尔为false,指针为nil等。

    1. 键值对初始化的格式如下:
    ins := 结构体类型名{
        字段1: 值,
        字段2: 值,
        ...
    }
    
    • 键值之间以“:”分隔;键值对之间以“,”分隔。
    2. 使用键值对填充结构体的例子
    type People struct {
        name string
        child *People
    }
    
    relation := &People{
        name:"爷爷",
        child: &People{
            name: "爸爸",
            child: &People{
                name: "我",
            },
        },
    }
    

    6.3.2 使用多个值得列表初始化结构体

    1. 多个值列表初始化结构体的书写格式

    多个值使用逗号分隔初始化结构体,例如:

    ins := 结构体类型名{
        字段1的值,
        字段2的值,
        ···
    }
    
    • 必须初始化结构体的所有字段。
    • 每一个初始值的填充顺序必须与字段在结构体中的声明顺序一致。
    • 键值对与值列表的初始化形式不能混用。
    2. 多个值列表初始化结构体的例子
    package main
    
    import "fmt"
    
    type Address struct {
        Province string
        City string
        ZipCode int
        PhoneNumber string
    }
    
    
    func main()  {
        addr := Address {
            "四川",
            "成都",
            610000,
            "15678903479",
        }
        fmt.Println(addr)
    }
    

    输出结果:

    {四川 成都 610000 15678903479}
    

    6.3.3 初始化匿名结构体

    匿名结构体没有类型名称,无须通过type关键字定义就可以直接使用。

    1. 匿名结构体定义格式和初始化写法

    匿名结构体的初始化写法由结构体定义和键值对初始化两部分组成。结构体定义时没有结构体类型名,只有字段和类型定义。

    ins := struct{
            字段1 字段类型
            字段2 字段类型
            ...
        }{
            初始化字段1:值,
            初始化字段2:值,
            ...
        }
    
    2. 使用匿名结构体的例子
    package main
    
    import "fmt"
    
    // 打印消息类型,传入匿名结构体
    func printMsgType(msg *struct{
        id int
        data string
    })  {
        fmt.Printf("%T\n", msg)
        fmt.Println(msg)
    }
    
    func main()  {
        msg := &struct {
            id int
            data string
        }{
            1024,
            "hello",
        }
        printMsgType(msg)
    }
    

    输出结果:

    *struct { id int; data string }
    &{1024 hello}
    

    匿名结构体在使用时需要重新定义,造成大量的重复代码,因此开发中较少使用。

    6.4 构造函数——结构体和类型的一系列初始化操作的函数封装

    Go语言没有提供构造函数的功能。结构体的初始化过程可以使用函数封装实现。

    6.4.1 模拟构造函数重载

    使用结构体描述一只猫。

    package main
    
    import "fmt"
    
    type Cat struct {
        Color string
        Name string
    }
    
    func NewCatByName(name string) *Cat {
        return &Cat{
            Name: name,
        }
    }
    
    func NewCatByColor(color string) *Cat {
        return &Cat{
            Color: color,
        }
    }
    
    func main()  {
        var cat1, cat2 *Cat
        cat1 = NewCatByName("san")
        cat2 = NewCatByColor("Black")
        fmt.Println(cat1, cat2)
    }
    

    6.4.2 带有父子关系的结构体的构造和初始化——模拟父级构造调用

    使用结构体描述猫和黑猫的关系时,将猫(Cat)的结构体嵌入黑猫(BlackCat)中,表示黑猫拥有猫的特性,然后再使用不同的构造函数分别构造出黑猫和猫两个结构体实例。

    package main
    
    import "fmt"
    
    type Cat struct {
        Color string
        Name string
    }
    
    type BlackCat struct {
        Cat  //嵌入Cat,类似于派生
    }
    
    // "构造基类"
    func NewCat(name, color string) *Cat {
        return &Cat{
            Name: name,
            Color: color,
        }
    }
    
    // "构造子类"
    func NewBlackCat(name, color string) *BlackCat  {
        cat := &BlackCat{}
        cat.Color = color
        cat.Name = name
        return cat
    }
    
    func main()  {
        cat := NewCat("san","write")
        blackCat := NewBlackCat("san","black")
        fmt.Println(cat, blackCat)
    }
    

    相关文章

      网友评论

          本文标题:第六章 结构体

          本文链接:https://www.haomeiwen.com/subject/phdxfltx.html