Go基础—5.结构体

TOC

一、Go结构体

结构体的基本定义和使用

结构体的定义格式如下:

ype 类型名 struct {  
    字段1 字段1类型  
    字段2 字段2类型  
    …  
}

基本的实例化结构体

结构体本身是一种类型,可以像整型、字符串等类型一样,以 var 的方式声明结构体即可完成实例化。
【示例】代码如下所示:

package main

import "fmt"

type Point struct {
    X,Y int
}

main() {
    var p Point
	p.X, p.Y = 1, 2
	fmt.Println(p)
}

指针类型的结构体

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

package main

import "fmt"

type Point struct {
    X,Y int
}

main() {
    p := new(Point)
	p.X, p.Y = 11, 12
	fmt.Println(*p)
}

结构体的地址实例化

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

package main

import "fmt"

type Point struct {
    X,Y int
}

main() {
    p := &Point{}
	p.X, p.Y = 11, 12
	fmt.Println(*p)
}

初始化结构体的成员变量

使用多个值的列表初始化

书写格式如下:

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

下面的例子描述了一段地址结构,地址要求具有一定的顺序。
【示例】代码如下所示:

package main

import "fmt"

type PeopleInfo struct {
	name   string
	age    int
	sex    string
	height float64
	weight float64
}

func main() {
	info := PeopleInfo{
		"Jack",
		23,
		"男",
		1.75,
		120.56,
	}
	fmt.Println("个人信息:", info)
}

使用键值对初始化

书写格式如下:

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

下面的例子加了字段名,可以不用像上面的结构体一样按照顺序来。
【示例】代码如下所示:

package main

import "fmt"

type PeopleInfo struct {
	name   string
	age    int
	sex    string
	height float64
	weight float64
}

func main() {
	info := PeopleInfo{
		name:   "Jack",
		height: 1.75,
		weight: 120.56,
		age:    23,
		sex:    "男",
	}
	fmt.Println("个人信息:", info)
}

初始化匿名结构体

书写格式如下:

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

在下面示例中,使用匿名结构体的方式定义和初始化一个结构体,并调用函数打印出结构体的值。
【示例】代码如下所示:

package main

import "fmt"

func print_info(info *struct {
	name   string
	age    int
	sex    string
	height float64
	weight float64
}) {
	// 使用动词%T打印info的类型
	fmt.Printf("结构体的类型: %T\n", info)
	// 打印info的数据信息
	fmt.Println("结构体的数据:", *info)
}

func main() {
	// 匿名初始化结构体
	info := &struct {
		name   string
		age    int
		sex    string
		height float64
		weight float64
	}{
		name:   "Jack",
		height: 1.75,
		weight: 120.56,
		age:    23,
		sex:    "男",
	}
	// 使用print_info()传入结构体数据打印数据
	print_info(info)
}
/* 运行结果如下
结构体的类型: *struct { name string; age int; sex string; height float64; weight float64 }
结构体的数据: {Jack 23 男 1.75 120.56}
*/

构造函数

模拟构造函数重载

使用结构体来描述猫的种类和颜色特征,可以通过下面方式来实现:

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

模拟父级构造调用

在基类的结构体中嵌入一个一个结构体,类似面向对象的"派生"。

package main

import "fmt"

type Cat struct {
	Color string
	Name  string
}

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

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

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

func main() {
	fmt.Println(NewCat("Casey"))
	fmt.Println(NewCatByColor("white"))
}
/* 运行结果如下
&{ Casey}
&{{white }}
*/

结构体内嵌

结构体内嵌特性:

  • 内嵌的结构体可以直接访问其成员变量。
    嵌入结构体的成员,可以通过外部结构体的实例直接访问。如果结构体有多层嵌入结构体,结构体实例访问任意一级的嵌入结构体成员时都只用给出字段名,而无须像传统结构体字段一样,通过一层层的结构体字段访问到最终的字段。例如,ins.a.b.c的访问可以简化为ins.c。
  • 内嵌结构体的字段名是它的类型名。

注意:嵌入结构体内部可能拥有相同的成员名,这样程序在编译的过程中会报错,编译器无法决定将值赋值给哪个结构体里的相同的成员名,所以在结构体里不能存在相同名字的字段
【示例】代码如下所示:

package main

import "fmt"

type Variety struct {
	v1, v2, v3, v4 string
}

type Prices struct {
	sphynx  int
	ragdoll int
	persian int
	siamese int
}

// 将Variety和Prices结构体嵌入其中
type Cats struct {
	name     string
	quantity int
	Variety
	Prices
}

func main() {
	cat := Cats{}
	// 对结构体里面的字段进行赋值
	cat.name = "miaomi"
	cat.quantity = 123
	cat.v1 = "sphynx"
	cat.v2 = "ragdoll"
	cat.v3 = "persian"
	cat.v4 = "siamese"
	cat.sphynx = 800
	cat.ragdoll = 1300
	cat.persian = 4700
	cat.siamese = 2300
	// 打印出第一次赋值整个结构体的结果
	fmt.Println(cat)
	// 使用结构体字面量
	cat2 := Cats{"xixi", 89, Variety{"sphynx", "ragdoll", "persian", "siamese"}, Prices{800, 1300, 4700, 2300}}
	// 打印出第二次赋值整个结构体的结果
	fmt.Println(cat2)
	// 分开打印出结构体Cats里面内嵌结构体和本身的字段的值
	fmt.Printf("cat2.name: %s, cat2.v1: %s, cat2.sphynx: %d", cat2.name, cat2.v1, cat2.sphynx)
}
/* 运行结果如下
{miaomi 123 {sphynx ragdoll persian siamese} {800 1300 4700 2300}}
{xixi 89 {sphynx ragdoll persian siamese} {800 1300 4700 2300}}
cat2.name: xixi, cat2.v1: sphynx, cat2.sphynx: 800
*/

初始化内嵌结构体

结构体内嵌初始化时,将结构体内嵌的类型作为字段名像普通结构体一样进行初始化。
【示例】代码如下所示:

package main

import "fmt"

type Variety struct {
	v1, v2, v3, v4 string
}

type Prices struct {
	sphynx  int
	ragdoll int
	persian int
	siamese int
}

type Cats struct {
	name     string
	quantity int
	Variety
	Prices
}

func main() {
	cat := Cats{
		name:     "miaomi",
		quantity: 123,
		Variety: Variety{
			v1: "sphynx",
			v2: "ragdoll",
			v3: "persian",
			v4: "siamese",
		},
		Prices: Prices{
			sphynx:  800,
			ragdoll: 1300,
			persian: 4700,
			siamese: 2300,
		},
	}
	// 打印出cat的结构
	fmt.Printf("%+v\n", cat)
	// 打印出cat的值
	fmt.Println(cat)
}
/* 运行结果如下
{name:miaomi quantity:123 Variety:{v1:sphynx v2:ragdoll v3:persian v4:siamese} Prices:{sphynx:800 ragdoll:1300 persian:4700 siamese:2300}}
{miaomi 123 {sphynx ragdoll persian siamese} {800 1300 4700 2300}}
*/