Golang Struct 示例教程
结构体是包括一组属性或字段的用户定义类型。,用来组织相关数据为一个整体。结构体可以描述现实世界实体的一组属性。
如果你有面向对象编程背景,可以认为结构体是轻量级的类,支持组合但不支持继承。
1. 定义结构体类型
下面定义新的结构体:
type Person struct {
FirstName string
LastName string
Age int
}
type
关键词定义新的类型,接着是用户类型名称,后面关键字struct
表明正在定义结构体。结构体的花括号内包括一组属性,每个属性有名称和类型。
注,相同类型可以合并:
type Person struct {
FirstName, LastName string
Age int
}
2. 声明并初始化结构体
2.1 声明结构体变量
和其他数据类型一样,可以声明struct类型变量:
// 定义 'Person' 类型变量
var p Person // 所有属性为默认值
上面代码创建Person类型变量,变量默认值为零值。对结构体来说零值就是所有属性都保持各自类型零值。因此,字符串属性为“”,Age为0
。
2.2 初始化结构体
也可以定义结构体变量时初始化:
var p = Person{"New", "Sing", 26}
注意,属性值需要按照一定顺序,且不能是部分字段值,错误如下:
var p = Person{"Rajeev"} // Compiler Error: too few values in struct initializer
2.3 命名字段初始化结构体
Go支持以键值对方式初始化结构体,是否按照顺序不重要:
var p = Person{FirstName: "Rajeev", LastName: "Singh", Age: 25}
我们可以以多行方式指定属性值增强可读性(此时必须有结尾的逗号):
var p = Person{
FirstName: "John",
LastName: "Snow",
Age: 45,
}
键值对方式初始化支持仅初始化部分字段,所有未初始化的字段值为零值:
var p = Person{FirstName: "Alien"} // LastName: "", Age: 0
var p = Person{} // FirstName: "", LastName: "", Age: 0
2.4 完整示例
package main
import (
"fmt"
)
// Defining a struct type
type Person struct {
FirstName string
LastName string
Age int
}
func main() {
// Declaring a variable of a `struct` type
var p Person // // All the struct fields are initialized with their zero value
fmt.Println(p)
// Declaring and initializing a struct using a struct literal
p1 := Person{"Rajeev", "Singh", 26}
fmt.Println("Person1: ", p1)
// Naming fields while initializing a struct
p2 := Person{
FirstName: "John",
LastName: "Snow",
Age: 45,
}
fmt.Println("Person2: ", p2)
// Uninitialized fields are set to their corresponding zero-value
p3 := Person{FirstName: "Robert"}
fmt.Println("Person3: ", p3)
}
# Output
{ 0}
Person1: {Rajeev Singh 26}
Person2: {John Snow 45}
Person3: {Robert 0}
3. 访问结构体变量及属性
本节介绍如果通过结构体变量和指针访问其属性,以及结构体变量及变量属性的可见性。
3.1 结构体变量访问属性
使用.
访问结构体属性:
package main
import (
"fmt"
)
type Car struct {
Name, Model, Color string
WeightInKg float64
}
func main() {
c := Car{
Name: "Ferrari",
Model: "GTC4",
Color: "Red",
WeightInKg: 1920,
}
// Accessing struct fields using the dot operator
fmt.Println("Car Name: ", c.Name)
fmt.Println("Car Color: ", c.Color)
// Assigning a new value to a struct field
c.Color = "Black"
fmt.Println("Car: ", c)
}
# Output
Car Name: Ferrari
Car Color: Red
Car: {Ferrari GTC4 Black 1920}
3.2 结构体指针访问属性
可以使用&
操作符获取结构体变量指针:
package main
import (
"fmt"
)
type Student struct {
RollNumber int
Name string
}
func main() {
// instance of student struct type
s := Student{11, "Jack"}
// Pointer to the student struct
ps := &s
fmt.Println(ps)
// Accessing struct fields via pointer
fmt.Println((*ps).Name)
fmt.Println(ps.Name) // Same as above: No need to explicitly dereference the pointer
ps.RollNumber = 31
fmt.Println(ps)
}
# Output
&{11 Jack}
Jack
Jack
&{31 Jack}
上面示例可以看到,通过结构体指针访问其属性无需显示解除引用。
3.3 使用new()方法创建结构体并返回指针
我们可以使用内置new方法创建结构体实例。new方法分配内存空间,并给每个属性设置零值,最后返回内存地址指针:
package main
import "fmt"
type Employee struct {
Id int
Name string
}
func main() {
// You can also get a pointer to a struct using the built-in new() function
// It allocates enough memory to fit a value of the given struct type, and returns a pointer to it
pEmp := new(Employee)
pEmp.Id = 1000
pEmp.Name = "Sachin"
fmt.Println(pEmp)
}
# Output
&{1000 Sachin}
3.4 暴露/隐藏结构体和结构体属性
任何结构体首字母为大写,则外部包可以直接访问。类似的结构体属性的首字母大写则暴露属性。
反之,所有以小写字母开头的仅在包内可见。请看示例:
example
main
main.go
model
address.go
customer.go
** customer.go**
package model
type Customer struct { // exported struct type
Id int // exported field
Name string // exported field
addr address // unexported field (only accessible inside package `model`)
married bool // unexported field (only accessible inside package `model`)
}
address.go
package model
// Unexported struct (only accessible inside package `model`)
type address struct {
houseNo, street, city, state, country string
zipCode int
}
main.go入口程序:
package main
import (
"fmt"
"example/model"
)
func main() {
c := model.Customer{
Id: 1,
Name: "Rajeev Singh",
}
c.married = true // Error: can not refer to unexported field or method
a := model.address{} // Error: can not refer to unexported name
fmt.Println("Programmer = ", c);
}
我们看到address
和 married
未暴露,不能在main包中访问。
4. 结构体是值类型
结构体是值类型。一个结构体变量赋值给另一个变量,则会产生一个拷贝给另一个变量。类似的,传递结构体给另一个函数,函数获得该结构体的拷贝。当然可以显示传递指针,避免拷贝大对象。
4.1 值类型拷贝
package main
import "fmt"
type Point struct {
X float64
Y float64
}
func main() {
// Structs are value types.
p1 := Point{10, 20}
p2 := p1 // A copy of the struct `p1` is assigned to `p2`
fmt.Println("p1 = ", p1)
fmt.Println("p2 = ", p2)
p2.X = 15
fmt.Println("\nAfter modifying p2:")
fmt.Println("p1 = ", p1)
fmt.Println("p2 = ", p2)
}
# Output
p1 = {10 20}
p2 = {10 20}
After modifying p2:
p1 = {10 20}
p2 = {15 20}
4.2 结构体变量比较
两个结构体如果相应属性相对则变量相等:
package main
import "fmt"
type Point struct {
X float64
Y float64
}
func main() {
// Two structs are equal if all their corresponding fields are equal.
p1 := Point{3.4, 5.2}
p2 := Point{3.4, 5.2}
if p1 == p2 {
fmt.Println("Point p1 and p2 are equal.")
} else {
fmt.Println("Point p1 and p2 are not equal.")
}
}
因为结构体是值类型,结果变量相等:
# Output
Point p1 and p2 are equal.
总结
本文介绍Golang结构体,通过示例介绍定义、实例化、访问属性。结构体是值对象,实际应用对于大结构体可以使用结构体指针传递参数,避免拷贝大对象影响性能。