Gostruct教程展示了如何在Golang中使用结构。
$ go version go version go1.18.1 linux/amd64
我们使用Go版本1.18。
结构
struct是包含字段集合的用户定义类型。它用于将相关数据分组以形成一个单元。Go结构可以比作没有继承特性的轻量级类。
Go结构体定义
结构是用type
关键字定义的。
type User struct { name string occupation string age int }
使用type
关键字创建新类型。它后面是类型的名称(用户)。struct
关键字表示我们正在创建一个结构。在大括号内,我们有一个字段列表。每个字段都有名称和类型。
去初始化结构
我们展示了如何在Go中初始化结构类型。
u := User{"John Doe", "gardener", 34}
创建了一个新的用户结构。结构字段使用大括号之间提供的值进行初始化。在这种情况下,字段的顺序是相关的。
u := User{ name: "John Doe", occupation: "gardener", age: 34, }
我们可以同时提供字段名称和值。在这种情况下,顺序并不重要。请注意,最后一个逗号是必需的。
u := User{}
如果我们省略大括号中的值,它们将被初始化为零值。
Go结构简单示例
下面是一个Gostruct的简单例子。
package main import "fmt" type User struct { name string occupation string age int } func main() { u := User{"John Doe", "gardener", 34} fmt.Printf("%s is %d years old and he is a %s\n", u.name, u.age, u.occupation) }
我们定义了一个包含三个字段的User
结构。
type User struct { name string occupation string age int }
我们声明了User
结构。
u := User{"John Doe", "gardener", 34}
我们初始化User
结构。
fmt.Printf("%s is %d years old and he is a %s\n", u.name, u.age, u.occupation)
我们打印User
结构的内容。
$ go run main.go John Doe is 34 years old and he is a gardener
Go结构访问字段
使用点运算符访问结构字段。
package main import "fmt" type User struct { name string occupation string age int } func main() { u := User{} u.name = "John Doe" u.occupation = "gardener" u.age = 34 fmt.Printf("%s is %d years old and he is a %s\n", u.name, u.age, u.occupation) }
我们创建一个空的User
结构。我们用值初始化字段并使用点运算符读取它们。
去匿名结构
可以在Go中创建匿名结构。匿名结构没有名字。它们只创建一次。
package main import "fmt" func main() { u := struct { name string occupation string age int }{ name: "John Doe", occupation: "gardener", age: 34, } fmt.Printf("%s is %d years old and he is a %s\n", u.name, u.age, u.occupation) }
匿名结构仅使用struct
关键字创建。结构的声明之后是它的初始化。
Go嵌套结构
Go结构可以嵌套。
package main import "fmt" type Address struct { city string country string } type User struct { name string age int address Address } func main() { p := User{ name: "John Doe", age: 34, address: Address{ city: "New York", country: "USA", }, } fmt.Println("Name:", p.name) fmt.Println("Age:", p.age) fmt.Println("City:", p.address.city) fmt.Println("Country:", p.address.country) }
在代码示例中,Address
结构嵌套在User
结构中。
fmt.Println("City:", p.address.city) fmt.Println("Country:", p.address.country)
要访问嵌套结构的字段,我们首先使用点运算符访问内部结构;然后我们访问相应的字段。
$ go run nested.go Name: John Doe Age: 34 City: New York Country: USA
Gostructpromotedfields
提升了嵌套匿名结构的字段;也就是说,无需引用嵌套结构即可访问它们。
package main import "fmt" type Address struct { city string country string } type User struct { name string age int Address } func main() { p := User{ name: "John Doe", age: 34, Address: Address{ city: "New York", country: "USA", }, } fmt.Println("Name:", p.name) fmt.Println("Age:", p.age) fmt.Println("City:", p.city) fmt.Println("Country:", p.country) }
在代码示例中,我们有一个嵌套的Address
结构。
type User struct { name string age int Address }
User
结构有一个嵌套的匿名Address
结构。该字段没有名称。
fmt.Println("City:", p.city) fmt.Println("Country:", p.country)
city
和country
字段被提升。它们通过直接引用父结构来访问。
$ go run main.go Name: John Doe Age: 34 City: New York Country: USA
Go结构函数字段
结构字段可以是函数。
package main import "fmt" type Info func(string, string, int) string type User struct { name string occupation string age int info Info } func main() { u := User{ name: "John Doe", occupation: "gardener", age: 34, info: func(name string, occupation string, age int) string { return fmt.Sprintf("%s is %d years old and he is a %s\n", name, age, occupation) }, } fmt.Printf(u.info(u.name, u.occupation, u.age)) }
在代码示例中,我们有User
结构。它的info
字段是一个名为Info
的函数。
Go结构指针
可以使用&
运算符或new
关键字创建指向结构的指针。使用*
运算符取消引用指针。
package main import "fmt" type Point struct { x int y int } func main() { p := Point{3, 4} p_p := &p (*p_p).x = 1 p_p.y = 2 fmt.Println(p) }
在代码示例中,我们创建了一个指向Point
结构的指针。
p_p := &p
&
运算符返回指向Point
结构的指针。
(*p_p).x = 1 p_p.y = 2
指针被*
运算符取消引用。Go还允许直接使用点运算符。
或者,我们可以使用new
关键字创建一个指向结构的指针。
package main import "fmt" type User struct { name string occupation string age int } func main() { u := new(User) u.name = "Richard Roe" u.occupation = "driver" u.age = 44 fmt.Printf("%s is %d years old and he is a %s\n", u.name, u.age, u.occupation) }
该示例使用new
关键字创建一个指向User
结构的新指针。
Go结构构造函数
Go中没有内置的构造函数。程序员有时会创建构造函数作为最佳实践。
package main import "fmt" type User struct { name string occupation string age int } func newUser(name string, occupation string, age int) *User { p := User{name, occupation, age} return &p } func main() { u := newUser("Richard Roe", "driver", 44) fmt.Printf("%s is %d years old and he is a %s\n", u.name, u.age, u.occupation) }
在代码示例中,我们有newUser
构造函数,它创建新的User
结构。该函数返回指向新创建的结构的指针。
Gostruct是一个值类型
Go结构体是值类型。当我们将一个结构变量分配给另一个结构变量时,会创建该结构的一个新副本。同样,当我们将一个结构传递给另一个函数时,该函数会收到该结构的一个新副本。
package main import "fmt" type User struct { name string occupation string age int } func main() { u1 := User{"John Doe", "gardener", 34} u2 := u1 u2.name = "Richard Roe" u2.occupation = "driver" u2.age = 44 fmt.Printf("%s is %d years old and he is a %s\n", u1.name, u1.age, u1.occupation) fmt.Printf("%s is %d years old and he is a %s\n", u2.name, u2.age, u2.occupation) }
在代码示例中,我们将一个结构分配给另一个结构。更改新结构的字段不会影响原始结构。
$ go run main.go John Doe is 34 years old and he is a gardener Richard Roe is 44 years old and he is a driver
这两个结构是不同的实体。
比较Go结构
如果所有相应的字段都相等,则Go结构相等。
package main import "fmt" type Point struct { x int y int } func main() { p1 := Point{3, 4} p2 := Point{3, 4} if p1 == p2 { fmt.Println("The structs are equal") } else { fmt.Println("The structs are not equal") } }
在代码示例中,我们比较了两个Point
结构。
$ go run main.go The structs are equal
去导出结构
以大写字母开头的命名结构被导出并可从其包外部访问。同样,导出以大写字母开头的结构字段。以小写字母开头的结构名称和字段仅在其包内可见。
$ go mod init exporting
我们使用gomodinit
命令创建一个新的Go模块。
go.mod main âââ main.go model âââ address.go âââ user.go
这是项目结构。
package model type User struct { Name string Occupation string age int }
User
结构的Name
和Occupation
字段被导出,而age
字段则没有。
package model type address struct { city string country string }
address
结构未导出。我们不能在main.go
文件中引用它。
package main import ( "exporting/model" "fmt" ) func main() { u := model.User{Name: "John Doe", Occupation: "gardener"} fmt.Printf("%s is a %s\n", u.Name, u.Occupation) }
在main.go
文件中,我们从exporting/model
导入Name
和Occupation
字段包。
去创建一个结构片
在下面的示例中,我们创建了一个结构切片。
package main import "fmt" type User struct { name string occupation string country string } func main() { users := []User{} users = append(users, User{"John Doe", "gardener", "USA"}) users = append(users, User{"Roger Roe", "driver", "UK"}) users = append(users, User{"Paul Smith", "programmer", "Canada"}) users = append(users, User{"Lucia Mala", "teacher", "Slovakia"}) users = append(users, User{"Patrick Connor", "shopkeeper", "USA"}) users = append(users, User{"Tim Welson", "programmer", "Canada"}) users = append(users, User{"Tomas Smutny", "programmer", "Slovakia"}) for _, user := range users { fmt.Println(user) } }
User
类型被定义。然后我们创建一个空的Userstruct切片。我们使用append
向切片添加元素。
过滤结构切片
在下一个例子中,我们过滤了一段Go结构。
package main import "fmt" type User struct { name string occupation string country string } func main() { users := []User{ {"John Doe", "gardener", "USA"}, {"Roger Roe", "driver", "UK"}, {"Paul Smith", "programmer", "Canada"}, {"Lucia Mala", "teacher", "Slovakia"}, {"Patrick Connor", "shopkeeper", "USA"}, {"Tim Welson", "programmer", "Canada"}, {"Tomas Smutny", "programmer", "Slovakia"}, } var programmers []User for _, user := range users { if isProgrammer(user) { programmers = append(programmers, user) } } fmt.Println("Programmers:") for _, u := range programmers { fmt.Println(u) } } func isProgrammer(user User) bool { return user.occupation == "programmer" }
在代码示例中,我们定义了一部分用户。我们创建一个仅包含程序员的新切片。
type User struct { name string occupation string country string }
User
结构具有三个字段。
users := []User{ {"John Doe", "gardener", "USA"}, {"Roger Roe", "driver", "UK"}, {"Paul Smith", "programmer", "Canada"}, {"Lucia Mala", "teacher", "Slovakia"}, {"Patrick Connor", "shopkeeper", "USA"}, {"Tim Welson", "programmer", "Canada"}, {"Tomas Smutny", "programmer", "Slovakia"}, }
这是User
结构的原始切片。
var programmers []User
过滤后的用户/程序员存储在程序员
切片中。
for _, user := range users { if isProgrammer(user) { programmers = append(programmers, user) } }
我们遍历users
切片,仅当用户满足isProgrammer
谓词时,才将当前用户添加到programmers
切片。
func isProgrammer(user User) bool { return user.occupation == "programmer" }
对于occupation
字段等于“程序员”的所有用户,IsProgrammer
谓词返回true。
$ go run main.go Programmers: {Paul Smith programmer Canada} {Tim Welson programmer Canada} {Tomas Smutny programmer Slovakia}
在本教程中,我们介绍了Golang中的结构。
列出所有Go教程。