5. 结构体

5.1 定义

type Name struct {
    ...
}

5.2 实例化

// 基本实例化
var name T
// new 关键字进行实例化
name := new(T)
// 取结构体的地址实例化
name := &T{} // 使用最广泛

5.3 初始化

// 键值对初始化结构体
type People struct {
    name  string
    child *People
}

relation := &People{
    name: "爷爷",
    child: &People{
        name: "爸爸",
        child: &People{
            name: "我",
        },
    },
}

// 多个值列表初始化结构体
type Address struct {
    Province    string
    City        string
    ZipCode     int
    PhoneNumber string
}

addr := Address{
    "四川",
    "成都",
    610000,
    "0",
}

// 匿名结构体初始化,匿名结构体在使用时需要重新定义,造成大量重复的代码,因此开发中较少使用。
msg := &struct {
    // 定义部分
    id   int
    data string
}{
    // 值初始化部分
    1024,
    "hello",
}

5.4 构造函数

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

// 多种方式创建和初始化结构体——模拟构造函数重载
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,
    }
}

// 带有父子关系的结构体的构造和初始化——模拟父级构造调用
type Cat struct {
    Color string
    Name  string
}

type BlackCat struct {
    Cat  // 嵌入Cat, 类似于派生
}

// “构造基类”
func NewCat(name string) *Cat {
    return &Cat{
        Name: name,
    }
}

// “构造子类”
func NewBlackCat(color string) *BlackCat {
    cat := &BlackCat{}
    cat.Color = color
    return cat
}

5.5 接收器

类似于 Kotlin 的拓展函数。

func (接收器变量 接收器类型) Name(params) (returns) {
    ...
}

type Bag struct {
    items []int
}

func (b *Bag) Insert(itemid int) {
    b.items = append(b.items, itemid)
}

func main() {
    b := new(Bag)
    b.Insert(1001)
}

// 为基本类型添加方法

type MyInt int

// 为 MyInt 添加 IsZero() 方法
func (m MyInt) IsZero() bool {
    return m == 0
}

5.6 内嵌模拟类的继承

import "fmt"

// 可飞行的
type Flying struct{}

func (f *Flying) Fly() {
    fmt.Println("can fly")
}

// 可行走的
type Walkable struct{}

func (f *Walkable) Walk() {
    fmt.Println("can walk")
}

// 人类
type Human struct {
    Walkable // 人类能行走
}

// 鸟类
type Bird struct {
    Walkable // 鸟类能行走
    Flying   // 鸟类能飞行
}

func main() {
    // 实例化鸟类
    b := new(Bird)
    fmt.Println("Bird: ")
    b.Fly()
    b.Walk()
    // 实例化人类
    h := new(Human)
    fmt.Println("Human: ")
    h.Walk()
}
// Output:
// Bird:
// can fly
// can walk
// Human:
// can walk

5.7 解析 JSON 数据

import (
    "encoding/json"
    "fmt"
)

// 定义手机屏幕
type Screen struct {
    Size       float32 // 屏幕尺寸
    ResX, ResY int     // 屏幕水平和垂直分辨率
}

// 定义电池
type Battery struct {
    Capacity int // 容量
}

// 生成json数据
func genJsonData() []byte {
    // 完整数据结构
    raw := &struct {
        Screen
        Battery
        HasTouchID bool // 序列化时添加的字段:是否有指纹识别
    }{
        // 屏幕参数
        Screen: Screen{
            Size: 5.5,
            ResX: 1920,
            ResY: 1080,
        },
        // 电池参数
        Battery: Battery{
            2910,
        },
        // 是否有指纹识别
        HasTouchID: true,
    }
    // 将数据序列化为json
    jsonData, _ := json.Marshal(raw)
    return jsonData
}

func main() {
    // 生成一段json数据
    jsonData := genJsonData()
    fmt.Println(string(jsonData))
    // 只需要屏幕和指纹识别信息的结构和实例
    screenAndTouch := struct {
        Screen
        HasTouchID bool
    }{}
    // 反序列化到screenAndTouch
    json.Unmarshal(jsonData, &screenAndTouch)
    // 输出screenAndTouch的详细结构
    fmt.Printf("%+v\n", screenAndTouch)
    // 只需要电池和指纹识别信息的结构和实例
    batteryAndTouch := struct {
        Battery
        HasTouchID bool
    }{}
    // 反序列化到batteryAndTouch
    json.Unmarshal(jsonData, &batteryAndTouch)
    // 输出screenAndTouch的详细结构
    fmt.Printf("%+v\n", batteryAndTouch)
}

5.8 SetFinalizer

如果需要在一个对象 obj 被从内存移除前执行一些特殊操作,比如写到日志文件中,可以通过如下方式调用函数来实现:

runtime.SetFinalizer(obj, func(obj *typeObj){})

results matching ""

    No results matching ""