Go语言结构体

Go语言不像c++,java,python等语言具有类的概念,也不支持"类"的继承与面向对象的概念,但是Go语言类似于c/c++语言可以使用结构体配合接口的方式表达比较复杂的数据结构,可以类比于python的元组,下面是关于Go语言结构体相关方面的知识点:

一. 类型别名和自定义类型

1.(1)类型别名语法规则: type TypeAlias = Type,TypeAlias是Type的一个别名,本质上TypeAlias与Type属于同一种类型,类似于一个人有对应名字的昵称,但是表示的都是同一个人,例如Go语言的内置基本数据类型byte和rune其实是uint8和int32的类型别名,我们在声明byte和rune的时候使用ctrl + 鼠标点击可以看到类型别名的定义;

(2)自定义类型语法规则: type a int,将a定义为int类型,a就是一种新的类型,具有int的特性;

我们可以使用type关键字自定义go语言内置的基本数据类型,例如int,int64等整型,float64浮点型,布尔型,自定义类型其实是定义了一种全新的类型;

(3)类型别名与自定义类型的区别,自定义类型其实是一种新的类型,类型别名本质上与定义的那个数据类型的类型是一样的,我们可以使用"%T"输出对应的类型:

package main

import "fmt"

func main() {
	type a int
	type b = int
	var (
		a1 a
		b1 b
	)
	fmt.Printf("%T\n", a1)
	fmt.Printf("%T\n", b1)
}

输出结果为:

main.a
int

二. 结构体

1. Go语言的结构体与c语言的结构体是很像的,其实是通过结构体来存储多个基本数据类型从而表达出更加复杂的数据结构满足相应的需求,需要使用type和struct关键字来定义结构体,定义的规则如下,其中类型名相当于是标识当前的结构体,字段名相当于是变量名,字段类型相当于是变量类型,结构体中可以封装多个字段:

type 类型名 struct {
      字段名 字段类型
      字段名 字段类型
      …
}

例如定义一个学生结构体,一个学生包含姓名,性别以及对应的编号信息,这样一个结构体就可以表示一个学生的相关信息:

type student struct {
    // 同类型的数据写在同一行
	name, sex string
	id        int
}

2. 结构体实例化

只有当结构体实例化的时候才会真正地分配内存,实例化之后才可以使用结构体中的元素,结构体类似于基本数据类型,所以也可以使用var关键字来声明结构体类型:

var 结构体实例 结构体类型

下面是实例化的例子,通过.来访问结构体中的字段:

package main

import "fmt"

type student struct {
	name, sex string
	id        int
}

func main() {
	var stu1 student
	stu1.name = "小明"
	stu1.sex = "男"
	stu1.id = 1
	fmt.Println(stu1)
}

3. new实例化操作创建指针类型结构体,可以使用new关键字对结构体进行实例化,得到的是结构体中的地址:

package main

import "fmt"

type student struct {
	name, sex string
	id        int
}

func main() {
    // stu2属于一个结构体指针
	var stu2 = new(student)
	stu2.name = "小张"
	stu2.sex = "男"
	stu2.id = 2
	fmt.Printf("%T\n", stu2)
	fmt.Printf("%v", stu2)
}

输出结果:

*main.student
&{小张 男 2} 

4. 取结构体的地址实例化

对结构体使用取地址操作其实是对于结构体类型进行了一次new实例化操作:

package main

import "fmt"

type student struct {
	name, sex string
	id        int
}

func main() {
	stu3 := &student{}
	fmt.Printf("%T\n", stu3)
	fmt.Printf("%v", stu3)

	stu3.name = "小强"
	stu3.sex = "女"
	stu3.id = 3
	fmt.Printf("%v", stu3)
}

5. 结构体初始化

(1)可以在定义结构体的时候进行初始化,使用键值对初始化,并且在初始化的时候可以不写键,直接写值,但是这种方式初始化结构体的时候需要满足:必须初始化所有的字段,初始化字段的顺序与结构体中字段的顺序保持一致;也可以对结构体指针进行键值对初始化,得到的是结构体指针:

package main

import "fmt"

type student struct {
	name, sex string
	id        int
}

func main() {
	stu4 := student{
		name: "xiaohong",
		sex:  "女",
		// 注意最后一个字段值的后面需要加上逗号
		id: 4,
	}
	fmt.Printf("%v\n", stu4)
	fmt.Printf("%T\n", stu4)

    // 省略键, 直接写值
	stu5 := student{
		"xiaorui",
		"男",
		5,
	}
	fmt.Printf("%v\n", stu5)
	fmt.Printf("%T\n", stu5)
    
    // stu6是一个结构体指针
    stu6 := &student{
		name: "xiaoxin",
		sex:  "女",
		id:   6,
	}
	fmt.Printf("%v\n", stu6)
	fmt.Printf("%T\n", stu6)
}

6. 结构体内存布局

package main

import "fmt"

type nums struct {
	a, b int
	c, d string
}

func main() {
	x := nums{
		a: 1,
		b: 1,
		c: "a",
		d: "a",
	}
	fmt.Printf("%p\n", &x.a)
	fmt.Printf("%p\n", &x.b)
	fmt.Printf("%p\n", &x.c)
	fmt.Printf("%p\n", &x.d)
}

输出结果:

0xc000074480
0xc000074488
0xc000074490
0xc0000744a0

7. 嵌套结构体

一个结构体可以嵌套另外一个结构体:

package main

import "fmt"

type student struct {
	name, sex string
	id        int
	Address   Address
}

type Address struct {
	province string
	city     string
}

func main() {
	stu7 := student{
		name: "xiaofei",
		sex:  "女",
		id:   7,
		Address: Address{
			province: "广东省",
			city:     "广州市",
		},
	}
	fmt.Printf("%v\n", stu7)
	fmt.Printf("%T\n", stu7)
}

8. 结构体字段的可见性

结构体中字段大写开头表示可公开访问,小写表示私有,所以如果是结构体的嵌套,被嵌套的结构体的字段需要大写才可以访问。

9. 结构体与json序列化

结构体与json字符串之间可以相互转化,使用json.Marshal()方法将结构体序列化json字符串,json.Unmarshal()反序列化为结构体

package main

import (
	"encoding/json"
	"fmt"
)

type Student struct {
	// 因为当前的结构体嵌套在另外一个结构体中所以被嵌套的结构体的字段需要大写后面才可以访问
	// 如果小写访问不了当前结构体中的元素
	Id   int
	Name string
}

//Class 班级
type Class struct {
	no       int
	Students []*Student
}

func main() {
	// c是一个结构体指针
	c := &Class{
		no:       2,
		Students: make([]*Student, 0, 200),
	}
	names := []string{"xiaozhang", "xiaoqiang", "xiaohong", "xiaohe", "xiaoxin"}
	for i := 0; i < 5; i++ {
		stu := &Student{
			Id:   i,
			Name: names[i],
		}
		c.Students = append(c.Students, stu)
	}
	//JSON序列化:结构体-->JSON格式的字符串
	data, err := json.Marshal(c)
	if err != nil {
		fmt.Println("json序列化失败")
		return
	}
	fmt.Printf("json:%s\n", data)
	//json反序列化:json格式的字符串转化为结构体
	str := `{"no":1,"Students":[{"id":1,"name":"xiaozhang"},{"id":2,"name":"xiaohe"}]}`
	c1 := &Class{}
	err = json.Unmarshal([]byte(str), c1)
	if err != nil {
		fmt.Println("json反序列化失败")
		return
	}
	fmt.Printf("%#v\n", c1)
}

你可能感兴趣的:(go,go)