结构体的声明
- 命名结构体,如下创建了名为
Employee
的新类型,而它可用于创建Employee
类型的结构体变量。
type Employee struct {
firstName, lastName string
age, salary int
}
- 匿名结构体,即声明结构体时可以不用声明一个新类型。
var employee struct {
firstName, lastName string
age int
}
创建命名的结构体
type Employee struct {
firstName, lastName string
age, salary int
}
func main() {
emp1 := Employee{
firstName: "Sam",
age: 25,
salary: 500,
lastName: "Anderson",
}
emp2 := Employee{"Thomas", "Paul", 29, 800}
}
上述代码,首先创建了一个命名的结构体Employee
。然后通过指定每个字段名的值,定义了结构体变量emp1
,字段名的顺序不一定要与声明结构体类型时的顺序相同。在定义emp2
时省略了字段名,在这种情况下,就需要保证字段名的顺序与声明结构体时的顺序相同。
创建匿名结构体
func main() {
emp3 := struct {
firstName, lastName string
age, salary int
}{
firstName: "Andreah",
lastName: "Nikola",
age: 31,
salary: 5000,
}
}
上述代码定义了一个匿名结构体变量emp3,它只是创建了一个新的结构体变量,而没有定义任何结构体类型。
结构体的零值
- 当定义好的结构体并没有被显示地初始化时,该结构体的字段将默认赋值为零值。
- 还可以为某些字段指定初始值,而忽略其它字段,这样,忽略的字段名会赋值为零值。
访问结构体的字段
- 点号操作符
.
用于访问结构体的字段。
结构体的指针
type Employee struct {
firstName, lastName string
age, salary int
}
func main() {
emp4 := &Employee{"Sam", "Anderson", 55, 6000}
fmt.Println("FirstName:", (*emp4).firstName)
fmt.Println("Age:", (*emp4).age)
// Go允许我们在访问字段时,使用 emp4.lastName 来代替显示的解引用 (*emp4).lastName
fmt.Println("LastName:", emp4.lastName)
fmt.Println("Salary:", emp4.salary)
}
匿名字段
当我们创建结构体时,字段可以只有类型,而没有字段名。这样的字段称为匿名字段。举个例子:
// 创建了一个Person结构体,含有两个匿名字段string和int
type Person struct {
string
int
}
func main() {
p := Person{"Naveen", 50}
fmt.Println(p) // {Naveen 50}
// 虽然匿名字段没有名称,但其实匿名字段的名称就默认为它的类型
// 所以不能含有两个相同类型的匿名字段
p.string = "Steve"
p.int = 45
fmt.Println(p) // {Steve 45}
}
嵌套结构体
结构体的字段有可能也是一个结构体,这样的结构体称为嵌套结构体。
type Address struct {
city string
}
type Person1 struct {
name string
age int
address Address
}
// 如果结构体中有匿名的结构体类型字段,则该匿名结构体里的字段就称为提升字段
// 提升字段就像是属于外部结构体一样,可以用外部结构体直接访问
type Person2 struct {
name string
age int
Address
}
func main() {
var p1 Person1
p1.name = "Naveen"
p1.age = 50
p1.address = Address{
city: "Chicago",
}
fmt.Println("Name:", p1.name) // Name: Naveen
fmt.Println("Age:", p1.age) // Age: 50
fmt.Println("City:", p1.address.city) // City: Chicago
var p2 Person2
p2.name = "Steve"
p2.age = 45
p2.Address = Address{
city: "New York",
}
fmt.Println("Name:", p2.name) // Name: Steve
fmt.Println("Age:", p2.age) // Age: 45
fmt.Println("City:", p2.city) // City: New York
}
结构体相等性
结构体是值类型。如果它的每一个字段都是可比较的,则该结构体也是可比较的。如果两个结构体变量对应的字段相等,则这两个变量也是相等的。如果结构体包含不可比较的字段,则结构体变量也不可比较。
结构体取代类
Go不支持类,而是提供了结构体,结构体中可以添加方法,这样就可以将数据和操作数据的方法绑定在一起,实现与类相似的效果。
可以通过提供参数化的构造器来隐藏类型,避免从其它包直接访问。通常做法:对应一个结构体应该提供一种名为NewT(parameters)
的函数,按照要求来初始化T
类型的变量。按照Go的惯例,如果一个包只含有一种类型,应该把函数命名为New(parameters)
而不是NewT(parameters)
。例子如下:
package employee
import "fmt"
// 隐藏的类型
type employee struct {
firstName string
lastName string
totalLeaves int
leavesTaken int
}
// 这里New是使用employee的唯一办法,安全可靠
func New(firstName string, lastName string, totalLeaves int, leavesTaken int) employee {
e := employee{firstName, lastName, totalLeaves, leavesTaken}
return e
}
// 注意,导出方法要大写
func (e employee) LeavesRemaining() {
fmt.Printf("%s %s has %d leaves remaining",
e.firstName, e.lastName, e.totalLeaves-e.leavesTaken)
}
reference:
https://studygolang.com/articles/12263
https://studygolang.com/articles/12630