第六章 结构体

2021-02-20  本文已影响0人  Benedict清水

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

6.1 定义结构体

结构体的定义格式如下:

type 类型名 struct {
    字段1 类型
    字段2 类型
    ...
}

示例如下:

type Point struct{
    x int
    y int
}

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

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

6.2.1 基本的实例化形式

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

var ins T
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)

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{}

下面使用结构体定义一个命令行指令,指令中包含名称、变量关联和注释等。对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)
}
上一篇 下一篇

猜你喜欢

热点阅读