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教程。
