Loading

结构体

十四、结构体

结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。比如你需要定义一些互相有联系的变量,而变量之间的类型不同。

举个实际的例子,保存图书馆的书籍记录,每本书有以下属性:titleauthorprice,此时就可以使用结构体类型。

1 定义结构体

结构体定义需要使用typestruct语句。struct语句定义一个新的数据类型,结构体中有一个或多个成员。type语句设定了结构体的名称。

type struct_variable_type struct {
   member definition
   member definition
   ...
   member definition
}
// struct_variable_type为自定义的结构体类型名称
// 在结构体内部定义成员(member definition)

一旦定义了结构体,就可以将它作为变量的声明

variable_name := structure_variable_type { key1: value1, key2: value2..., keyn: valuen}

示例:

type Books struct {
	title  string
	author string
	price  int
}

func main() {
	var book Books // 声明变量为Books结构体类型
}

2 访问结构体成员

果要访问结构体成员,需要使用点. 操作符。

type Books struct {
   title  string
   author string
   price  int
}

func main() {
   var book Books // 声明但未初始化赋值
   fmt.Println(book.price) // 未赋值时,结构体为零值
}

3 结构体成员赋值

可以在声明时赋值;也可以先声明,再使用.操作符赋值。

type Books struct {
	title  string
	author string
	price  int
}
func main() {
	var book = Books{
		title:  "西游记",
		author: "吴承恩",
		price:  60,
	}
    // 也可以如下方式赋值
	//book.title = "西游记"
	//book.author = "吴承恩"
	//book.price = 60
	fmt.Println(book)
}

你可以为结构体的部分成员赋值,此时剩下的成员会被赋值为零值。

4 结构体的导出

定义结构体及其成员时,仍遵循大写导出,小写不导出的规则。如下:

type Books struct { // 大写结构体名字,可以导出,外部包可以访问
   title  string // 小写成员名字,不能被导出,外部包无法访问
   author string // 小写成员名字,不能被导出,外部包无法访问
   Price  int // 大写成员名字,可以导出,外部包可以访问
}

如果想要让这个结构体所有成员被外部访问,需要将它们大写。

5 结构体的函数传递

你可以像其他数据类型一样将结构体类型作为参数传递给函数,并且可以访问内部成员。

type Books struct {
	Title  string
	Author string
	Price  int
}

func change(book Books) {
	book.Title = "红楼梦"
	book.Author = "曹雪芹"
	book.Price = 50
}
func main() {

	var book = Books{
		Title:  "西游记",
		Author: "吴承恩",
		Price:  60,
	}
	fmt.Println(book)
	change(book) // 结构体按值传递,在函数内部的更改不影响原来的值
	fmt.Println(book)
}

在函数内修改结构体,原来的结构体不会改变。

6 结构体指针与结构体的函数引用传递

要想在函数内更改结构体,可以利用结构体指针。相当于结构体的引用传递。

type Books struct {
	Title  string
	Author string
	Price  int
}

func change(book *Books) {
	book.Title = "红楼梦"
	book.Author = "曹雪芹"
	book.Price = 50
}
func main() {

	var book = Books{
		Title:  "西游记",
		Author: "吴承恩",
		Price:  60,
	}
	var ptr *Books = &book // 定义结构体指针,指向book
	fmt.Println(book)
	change(ptr) // 传递指针,通过指针修改原结构体
	fmt.Println(book) // 此时是引用传递,函数内的更改在外部生效
}

7 匿名结构体

我们之前定义的结构体称为命名结构体,因为我们创建了新的类型;匿名结构体是是一个变量,不创建新的类型。

func main() {
   // 匿名结构体
   var Book struct {
      title  string
      author string
      price  int
   }
   // 结构体赋值
   Book.title = "西游记"
   Book.author = "吴承恩"
   Book.price = 50
   fmt.Println(Book)
}

也可以在声明同时赋值

func main() {
	// 创建匿名结构体,使用变量Book接收它,并为它的成员赋值
    Book := struct {
		title  string
		author string
		price  int
	}{
		title:  "西游记",
		author: "吴承恩",
		price:  50,
	}
	fmt.Println(Book)
}

8 结构体嵌套

结构体内部还可以定义结构体。示例:

type Book struct {
	Title  string
	Author struct {
		Name string
		Age  int
	}
	price int
}

func main() {
	book := Book{
		Title: "西游记",
		Author: struct {
			Name string
			Age  int
		}{
			Name: "吴承恩",
			Age:  18,
		},
		price: 60,
	}
	fmt.Println(book)
}

9 匿名字段

定义结构体时,成员字段可以只有类型而没有字段名,这种形式的结构体字段为匿名字段。

// 定义匿名字段
type Book struct {
	string
	int
}

func main() {
	book := Book{
		string: "红楼梦",
		int:    60,
	}
	// 如果字段没有名称,那么默认它的名称为它的类型
	fmt.Println(book)
}

如果字段没有名称,那么默认它的名称为它的类型。比如string字段和int字段。

10 结构体比较

结构体是值类型(通过函数传递也可以看出来),如果它的所有字段都可比较,则该结构体也是可比较的;如果结构体包含不可比较的字段,则结构体也不可比较。

11 字段提升

如果结构体中有匿名结构体类型的字段,该匿名结构体里的字段就称为提升字段。这些字段自动提升,可以用外部结构体直接访问。

type Book struct {
	title  string
	author // 匿名字段
}

type author struct {
	name string
	age  int
}

如上,Book中有一个匿名字段authorauthor是结构体类型,包含nameage两个成员,那么我们通过Book就可以访问到它们。

posted @ 2021-12-10 11:48  yyyz  阅读(187)  评论(0编辑  收藏  举报