over-golang/01-基础语法/06-值类型-4-结构体.md
2021-07-02 18:11:59 +08:00

3.2 KiB
Raw Permalink Blame History

一 结构体的基本使用

结构体可以用来声明新的类型,作为其他类型的属性/字段的容器,如下定义一个学生结构体:

type Person struct {
	name string
	age int
}

//按顺序初始化:每个成员都必须初始化
var p1 Person = Person{"lisi", 20}

//制定成员初始化:没有被初始化的,自动赋零值
p2 := Person{age:30}
	
// new 申请结构体
p3 := new(Person)      //被new生成的结构体实例其实是指针类型
p3.name = "zs"          //这里的.语法只是语法糖将p3.name转换成了(*p3).name
p3.age = 27
	
//直接声明
var s4 Person
p4.name = "ww"
p4.age = 30

贴士:

  • struct的结构中的类型可以是任意类型且存储空间是连续的其字段按照声明时的顺序存放
  • 如果结构体的所有的成员都是可以比较的,那么结构体本身也是可以比较的,使用 == != ,不支持 > 和 <
  • 如果结构体的成员要被包外调用,需要大写首字母。

二 结构体地址与实例化

前面说过对结构体的new其实是生成了一个指针类型。其实对结构体进行&取地址操作时,也可以视为对该类型进行一次new的实例化操作。

ins := &T{}

# T是结构体类型
# ins为结构体的实例类型为*T是指针类型

四 内嵌结构体

当前结构体可以直接访问其内嵌结构体的内部字段:

package main

import "fmt"

type Animal struct {
	Age int
}

type Person struct {
	Animal
	Name string
}

type Student struct {
	Person
	ClassName string
}

func main() {

	// 初始化方式1
	s1 := Student{
		Person{
			Animal: Animal {
				Age: 15,
			},
			Name:"lisi",
		},
		"一班",
	}
	fmt.Println(s1.Age)				// 正确输出15
	fmt.Println(s1.Person.Name)		// 正确输出lisi

	// 初始化方式2
	var s2 Student
	s2.Name = "zs"
	s2.Age = 30
	s2.ClassName = "二班"
	fmt.Println(s2.Age)				// 正确输出30
	fmt.Println(s2.Person.Name)		// 正确输出zs
}

四 匿名字段

结构体的字段名与类型一一对应,如果不提供名字,则为匿名字段。

匿名字段如果是一个struct这个struct拥有的全部字段都被隐式引入了当前的struct。

type Person struct {
    name string
    age int
}
    
type Student struct {
    Person                   // 匿名字段那么默认Student就包含了Person的所有字段
    classroom string
}

不仅仅是struct其他所有内置类型和自定义类型都可以作为匿名字段

package main

import "fmt"
type Person struct {
	name string
	age int
}

type course []string

type Student struct {
	Person 				// 匿名字段struct
	course				// 内置一个切片类型
	classroom string
}

func main() {

	// 创建一个学生
	s := Student{Person:Person{"LiLei", 17}, classroom:"二班"}

	// 访问该学生字段
	fmt.Println("name = ", s.name)
	fmt.Println("classroom =  ", s.classroom)

	// 修改学生的课程
	s.course = []string{"语文", "美术"}
	fmt.Println("course = ", s.course)			// [语文 美术]
}

贴士如果Person和Student中都有同一个字段那么Go会优先访问当前层。例如二者都有tel字段,那么s.tel将会访问的是Student中的数据。