5.1. 结构体

Go语言通过自定义的方式形成新的类型,结构体是类型中带有成员的复合类型。 Go语言使用结构体和结构体成员来描述真实世界的实体和实体对应的各种属性。

Go语言中的类型可以被实例化,使用new或“&”构造的类型示例的类型是类型的指针。

结构体中由一系列成员变量组成,这些成员变量也被称为“字段”。字段有以下特征: - 字段用于自己的类型和值 - 字段名必须唯一 - 字段的类型也可以是结构体,甚至字段所在结构体的类型。

Go语言中没有“类”的概念,也不支持“类”的继承等面向对象的概念。

Go语言不仅任务结构体能拥有方法,且每种自定义类型也可以拥有自己的方法。

5.1.1. 1.定义结构体

Go语言的关键字type可以将各种基本类型定义为自定义类型,基本类型包括:整型、字符串、布尔等。 结构体是一种复合的基本类型,通过type定义为自定义类型后,使结构体更便于使用。

结构体的定义格式如下:

type 类型名 struct {
字段1 字段1 类型
字段2 字段2 类型
}
· 类型名: 标识自定义结构体的名称,在同一个包内不能重复

· struct{} :表示结构体类型,type类型名struct{}可以理解将struct{}结构体定义为类型名的类型。

· 字段1、字段2···: 表示结构体字段名。结构体中的字段名必须唯一。

· 字段1类型、字段2类型···:表示结构体字段的类型。

表示一个包含X和Y整型分量的点结构

type Point struct {
    X int
    Y int
}

同类型的变量可以写在一行

type Color struct {
    red, green, blue byte
}

5.1.2. 2.实例化结构体-为结构体分配内存并初始化

2.1 基本的实例化形式

基本实例化格式如下:

var ins T

· ins 为结构体实例

· T 为结构体类型

实例化结构体 Point,如下:

func main() {
    var p Point
    p.X = 19
    p.Y = 20
    fmt.Println(p.X)
    fmt.Println(p.Y)
}

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

2.2创建指针类型的结构体

Go语言中,还可以使用new关键字对类型进行实例化,结构体在实例化后会形成指针类型的结构体。

使用new格式如下:

ins :=new(T)

· T 为类型,可以是结构体、整型、字符串等

· ins: T类型被实例化后保存到ins变量中,ins的类型为*T,属于指针。

package main

type Player struct {
    Name        string
    HealthPoint int
    MagicPoint  int
}

func main() {
    tank := new(Player)
    tank.Name = "Hujianli01"
    tank.HealthPoint = 300
    // 通过new实例化的结构体实例在成员赋值上与基本实例化的写法一致
}

// Go语言为了方便开发者访问结构体指针的成员变量,使用了语法糖(Syntacticsugar)技术,将ins.Name形式转换为(*ins).Name。

2.3取结构体的地址实例化

ins :=&T{}

· T表示结构体类型
· ins为结构体的实例,类型为*T,是指针类型
package main

import "fmt"

type Command struct {
    Name    string //指令的名称
    Var     *int   // 指令绑定的变量
    Comment string // 指令的注释
}

var version int = 1

func newCommand(name string, varref *int, comment string) *Command {
    return &Command{
        Name:    "version",
        Var:     nil,
        Comment: "show version",
    }
}

func main() {
    //cmd := &Command{}
    //cmd.Name = "hujianli722"
    //cmd.Var = &version
    //cmd.Comment = "show version"
    cmd := newCommand("version", &version, "show version")
    fmt.Println(cmd)

}

5.1.3. 3.初始化结构体的成员变量

初始化有两种形式:

  • 一种是字段“键值对”形式

键值对形式的初始化适合选择性填充字段较多的结构体

  • 多个值的列表形式。

多个值的列表形式适合填充字段较少的结构体

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

键值对初始化结构体的格式:

ins := 结构体类型名 {
    字段1:字段1的值
    字段2:字段2的值
}

3.2使用键值对填充结构的例子

package main

import "fmt"

type People struct {
    name string
    // 结构体的结构体指针字段,类型是*People
    child *People
}

func main() {
    // People取地址后,锡恩超类型为*People的实例
    relation := &People{
        name: "爷爷",
        // 使用取地址初始化一个People。结构体成员中只能包含结构体的指针类型。
        child: &People{
            name: "爸爸",
            child: &People{
                name: "我",
            },
        },
    }
    fmt.Println(relation.name)          //爷爷
    fmt.Println(relation.child.name)    //爸爸
    fmt.Println(relation.child.child.name)  //我
}

3.3使用多个值的列表初始化结构体

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

ins := 结构体类型名{
    字段1的值,
    字段2的值,
}
package main

import "fmt"

type Address struct {
    Province    string
    City        string
    ZipCode     int
    PhoneNumber string
}

func main() {
    addr := Address{
        "四川",
        "成都",
        61000000,
        "0",
    }
    fmt.Println(addr)
}

通常结构体都是通过指针的方式使用,可以使用一种简单的方式创建、初始化一个struct类型的变量并获取它的地址。

package main

import "fmt"

type Point struct {
    x, y int
}

func main() {
    pp := &Point{1, 2}
    fmt.Println(pp)  // &{1 2}
    fmt.Println(*pp) //{1 2}

    pp2 := new(Point)
    *pp2 = Point{2, 3}
    fmt.Println(pp2)  //&{2 3}
    fmt.Println(*pp2) //{2 3}

}

3.4 结构体的比较

结构体的所有成员都是可以比较的,那么这个结构体就是可以比较的。

两个结构体的比较可以用==或者!=。其中==操作比较的是两个结构体变量的成员变量。

package main

import "fmt"

type Point struct {
    X, Y int
}

type address struct {
    hostname string
    port     int
}

func main() {
    q := Point{1, 2}
    p := Point{2, 3}
    fmt.Println(p.X == q.X && p.Y == q.Y) // false
    fmt.Println(p == q)                   // false

    // 可比较的结构体可以作为map键类型
    hits := make(map[address]int)
    hits[address{"golang.org", 443}]++
    fmt.Println(hits)
}

5.1.4. 4.初始化匿名结构体

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

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

ins := struct{
    // 匿名结构体字段定义
    字段1 字段类型1
    字段2 字段类型2
    ......
}{
    // 字段值初始化
    初始化字段1: 字段1的值
    初始化字段2: 字段2的值
    ......
}

键值对初始化部分是可选的,不初始化成员时,匿名结构体的格式变为:

ins := struct {
    字段1 字段类型1
    字段2 字段类型2
    .....
} { }
package main

import (
    "fmt"
)

// 打印消息类型,传入匿名结构体
func printMsgType(msg *struct {
    id   int
    data string
}) {
    // 使用动词%T打印msg的类型
    fmt.Printf("%T\n", msg)
    fmt.Println(msg.data)
    fmt.Println(msg.id)
}

func main() {
    // 实例化一个匿名结构体
    msg := &struct {        //定义部分
        id int
        data string
    }{                      //值初始化部分
        1024,
        "hello",
    }
    printMsgType(msg)

}

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