本节重点:
- 学会并使用结构体
概念
数组、切片和 Map 可以用来表示同一种数据类型的集合,但是当我们要表示不同数据类型的集合时就需要用到结构体。
结构体是由零个或多个任意类型的值聚合成的实体,它可以用于将数据分组为一个单元而不是将它们中的每一个作为单独的值。
声明一个结构体
Go 里面用关键字 type
和 struct
用来定义结构体,语法如下:
type StructName struct{
FieldName type
}
我们来定义一个学生结构体:
package main
import "fmt"
type Student struct {
Age int
Name string
}
func main() {
stu := Student{
Age: 18,
Name: "name",
}
fmt.Println(stu)
// 在赋值的时候,字段名可以忽略
stu2 := Student{20, "new name"}
fmt.Println(stu2)
return
}
上述代码 5 行声明了一个Student
的结构体。而在第 11 行,通过指定每个字段名的值,我们定义了结构体变量 stu
。字段名的顺序不一定要与声明结构体类型时的顺序相同。在这里,我们改变了 Age
的位置,将其移到了末尾。这样做也不会有任何的问题。
但是在第 18 行。定义 stu2
时我们省略了字段名。在这种情况下,就需要保证字段名的顺序与声明结构体时的顺序相同。请不要使用这种语法,因为它很难确定哪个值是哪个字段的。我们在这里指定这种格式只是为了理解这也是一种有效的语法:)
上述代码输出如下:
{18 name}
{20 new name}
创建匿名结构体
可以在不创建新数据类型的情况下声明结构。这些类型的结构称为匿名结构。
package main
import (
"fmt"
)
func main() {
emp3 := struct {
firstName string
lastName string
age int
salary int
}{
firstName: "Andreah",
lastName: "Nikola",
age: 31,
salary: 5000,
}
fmt.Println("Employee 3", emp3)
}
在上述程序的第 8 行中,定义了一个匿名结构变量 emp3
。正如我们已经提到的,这个结构被称为匿名的,因为它只创建一个新的结构变量 emp3
,并没有像命名结构那样定义任何新的结构类型。
该程序输出:Employee 3 {Andreah Nikola 31 5000}
获取结构的各个字段
点.
运算符用于访问结构的各个字段。
package main
import (
"fmt"
)
type Employee struct {
firstName string
lastName string
age int
salary int
}
func main() {
emp6 := Employee{
firstName: "Sam",
lastName: "Anderson",
age: 55,
salary: 6000,
}
fmt.Println("First Name:", emp6.firstName)
fmt.Println("Last Name:", emp6.lastName)
fmt.Println("Age:", emp6.age)
fmt.Printf("Salary: $%d\n", emp6.salary)
emp6.salary = 6500
fmt.Printf("New Salary: $%d", emp6.salary)
}
上面程序中的emp6.firstName用于获取结构体emp6
的字段firstName
的内容。在第25行号,我们修改员工的工资。该程序打印:
First Name: Sam
Last Name: Anderson
Age: 55
Salary: $6000
New Salary: $6500
结构体的指针
也可以创建指向结构的指针。
package main
import (
"fmt"
)
type Employee struct {
firstName string
lastName string
age int
salary int
}
func main() {
emp8 := &Employee{
firstName: "Sam",
lastName: "Anderson",
age: 55,
salary: 6000,
}
fmt.Println("First Name:", (*emp8).firstName)
fmt.Println("Age:", (*emp8).age)
}
在上面程序中,emp8
是一个指向结构体 Employee
的指针。(*emp8).firstName
表示访问结构体 emp8
的 firstName
字段。该程序会输出:
First Name: Sam
Age: 55
Go 语言允许我们在访问 firstName
字段时,可以使用 emp8.firstName
来代替显式的解引用 (*emp8).firstName
。
package main
import (
"fmt"
)
type Employee struct {
firstName string
lastName string
age int
salary int
}
func main() {
emp8 := &Employee{
firstName: "Sam",
lastName: "Anderson",
age: 55,
salary: 6000,
}
fmt.Println("First Name:", emp8.firstName)
fmt.Println("Age:", emp8.age)
}
在上面的程序中,我们使用emp8.firstName
来访问 firstName
字段,该程序会输出:
First Name: Sam
Age: 55
匿名字段
可以创建具有仅包含类型而没有字段名称的字段的结构。这些类型的字段称为匿名字段。
下面的代码片段创建了一个结构Person
,它有两个匿名字段string
和int
type Person struct {
string
int
}
即使匿名字段没有明确的名称,默认情况下匿名字段的名称就是其类型的名称。例如,在上面的 Person
结构中,虽然字段是匿名的,但默认情况下它们采用字段类型的名称。所以Person
结构体有 2 个字段,分别为string
和int
.
package main
import (
"fmt"
)
type Person struct {
string
int
}
func main() {
p1 := Person{
string: "naveen",
int: 50,
}
fmt.Println(p1.string)
fmt.Println(p1.int)
}
在上面程序的第 17 行和第 18 行,我们访问了 Person
结构体的匿名字段,我们把字段类型作为字段名,分别为 “string” 和 “int”。上面程序的输出如下:
naveen
50
嵌套结构体
一个结构可能包含一个字段,而该字段又是一个结构。这些类型的结构称为嵌套结构。
package main
import (
"fmt"
)
type Address struct {
city string
state string
}
type Person struct {
name string
age int
address Address
}
func main() {
p := Person{
name: "Naveen",
age: 50,
address: Address{
city: "Chicago",
state: "Illinois",
},
}
fmt.Println("Name:", p.name)
fmt.Println("Age:", p.age)
fmt.Println("City:", p.address.city)
fmt.Println("State:", p.address.state)
}
上述程序中Person
的结构有一个字段address
,该字段address
又是一个结构。该程序打印:
Name: Naveen
Age: 50
City: Chicago
State: Illinois
注意:
- 当定义一个结构体变量,但是没有给它提供初始值,则对应的字段被赋予它们各自类型的零值。