一、基本说明

结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。

二、结构体声明

type 结构体名称 struct{
	field type
	field type
}

例子:

type Dog struct {
	Name  string
	Age   int
	Color string
}

注:在创建一个结构体变量后,如果没有给字段赋值,都应该对应一个零值(默认值),布尔类型为false,数值类型为0,字符串为"",指针、slice和map的零值时nil,即没有分配空间。

三、结构体变量和访问结构体字段

  1. 方式一:直接声明
var dog Dog
  1. 方式二:{}
package main

import (
	"fmt"
)

type Dog struct {
	Name  string
	Age   int
	Color string
}

func main() {
	dog := Dog{"来福", 3, "白色"}
	fmt.Printf("dog=%v\n", dog)
}

输出结果:

dog={来福 3 白色}
  1. 方式三:new()
package main

import (
	"fmt"
)

type Dog struct {
	Name  string
	Age   int
	Color string
}

func main() {
	dog := new(Dog)
	// dog是一个指针,因此标准的给字段赋值应该是(*dog).Name = "来福" (*dog).Age = 3 (*dog).Color = "白色"
	// go设计者为了程序员使用方便,底层会对dog.Name = "来福"进行处理,会给dog加上取值运算(*dog).Name = "来福"
	dog.Name = "来福"  // 等价于(*dog).Name = "来福"
	dog.Age = 3      // 等价于(*dog).Age = 3
	dog.Color = "白色" // 等价于(*dog).Color = "白色"
	fmt.Printf("dog=%v\n", *dog)
}

输出结果:

dog={来福 3 白色}
  1. 方式四:
package main

import (
	"fmt"
)

type Dog struct {
	Name  string
	Age   int
	Color string
}

func main() {
	dog := &Dog{"来福", 3, "白色"}
	fmt.Printf("dog=%v\n", *dog)
}

输出结果:

dog={来福 3 白色}

说明:

  1. 第三种方式和第四种方式返回的是结构体指针
  2. 结构体指针访问字段的标准方式应该是:(*结构体指针).字段名,比如(*dog).Name = "来福"
  3. 但是go做了一个简化,也支持结构体指针.字段名,比如:dog.Name = "来福",更加符合程序员使用习惯,go编译器底层对dog.Name做了转化(*dog).Name

四、结构体和结构体变量的区别

  1. 结构体是自定义的数据类型,代表一类事物
  2. 结构体变量(实例)是具体的,实际的,代表一个具体变量

五、结构体在内存中的示意图

go语言struct_struct

六、注意细节

  1. 结构体所有字段在内存中是连续分布的
package main

import (
	"fmt"
)

type Point struct {
	x, y int
}

type Rect struct {
	LeftUp, RightDown Point
}

func main() {
	rect := Rect{Point{10, 20}, Point{30, 40}}
	fmt.Printf("rect.LeftUp.x地址=%v\n,rect.LeftUp.y地址=%v\n,rect.RightDown.x地址=%v\n,rect.RightDown.y地址=%v\n",
		&rect.LeftUp.x, &rect.LeftUp.y, &rect.RightDown.x, &rect.RightDown.y)
}

输出结果:

rect.LeftUp.x地址=0xc0000124e0
,rect.LeftUp.y地址=0xc0000124e8
,rect.RightDown.x地址=0xc0000124f0
,rect.RightDown.y地址=0xc0000124f8
  1. 结构体是用户单独定义的类型,和其他类型进行转换时需要有完全相同的字段(名字、个数和类型)
package main

import (
	"fmt"
)

type A struct {
	Num  int
	Num2 int
}

type B struct {
	Num  int
	Num2 int
}

func main() {
	var a A
	var b B
	a = A(b) // 可以转换,但是有要求,就是结构体字段要完全一样(包括:名字,类型,个数,顺序)
	fmt.Println("a=", a, "b=", b)
}

输出结果:

a= {0 0} b= {0 0}
  1. 结构体进行type重新定义(相当于取别名),Golang认为是新的数据类型,但是相互间可以强转
package main

import (
	"fmt"
)

type integer int

func main() {
	var i integer
	var j int
	j = int(i)
	fmt.Println("i=", i, "j=", j)
}

输出结果:

i= 0 j= 0
  1. struct的每个字段上,可以写上一个tag,该tag可以通过反射机制获取,常见的使用场景就是序列化和反序列化
package main

import (
	"encoding/json"
	"fmt"
)

type Dog struct {
	Name  string `json:"name"` // `json:"name"`就是struct tag
	Age   int    `json:"age"`
	Color string `json:"color"`
}

func main() {
	dog := Dog{"来福", 3, "白色"}
	// 将dog变量序列化为json字符串
	// json.Marshal函数中使用反射
	jsonStr, err := json.Marshal(dog)
	if err != nil {
		fmt.Println("json转换错误")
	}
	fmt.Println("dog=", string(jsonStr))
}

输出结果:

dog= {"name":"来福","age":3,"color":"白色"}