2.2. 常用注意事项 1到7 基础
g g study,d d up!
常用注意事项
1. 结构体的字段可以是任何类型,包括基本类型,指针类型和其他结构体类型等。
package main
import "fmt"
type Person struct {
name string
age int
address *Address
}
type Address struct {
street string
city string
}
func main() {
p := Person{name: "Alice", age: 30, address: &Address{street: "123 Main St", city: "Anytown"}}
fmt.Println(p.name)
fmt.Println(p.age)
fmt.Println(p.address.street)
fmt.Println(p.address.city)
}
在这个例子中,我们定义了两个结构体类型:Person
和Address
。Person
结构体具有三个字段:name
是字符串类型,age
是整数类型,address
是指向Address
结构体的指针类型。Address
结构体具有两个字段:street
和city
,都是字符串类型。
在main()
函数中,我们创建了一个Person
结构体的实例,并为每个字段设置了值。然后,我们使用点运算符访问每个字段并打印它们的值。
2. 结构体的字段名称可以是任何有效的标识符,且每个字段必须有一个唯一的名称。
名称重复就报错。这里不演示了。如果录制视频,我就在这演示一下,现在是文档你自己复制代码,整两个name 试试看。
3. 结构体可以嵌套,这意味着一个结构体可以包含其他结构体类型的字段。
当我们创建结构体时,我们可以将其他结构体类型嵌套到当前结构体中,形成嵌套结构体。
下面是一个简单的例子,其中定义了两个结构体:Person
和 Employee
,其中 Employee
结构体嵌套了 Person
结构体。
type Person struct {
name string
age int
address string
}
type Employee struct {
id int
salary float64
person Person
}
func main() {
p := Person{"Tom", 25, "123 Main Street"}
e := Employee{1, 5000.0, p}
fmt.Println(e.id, e.salary, e.person.name, e.person.age, e.person.address)
}
在上面的示例中,Employee
结构体嵌套了 Person
结构体,并使用 person
字段来存储 Person
结构体的值。在 main()
函数中,我们创建了一个 Person
类型的值 p
,并将其传递给 Employee
结构体的 person
字段。最后,我们使用 fmt.Println()
函数打印 Employee
结构体的所有字段。
4. 可以使用结构体字面值初始化结构体变量。例如,可以使用以下方式初始化Person结构体变量:
person := Person{name: "Alice", age: 25}
5. 结构体可以作为函数参数和返回值。如果结构体很大,最好通过指针传递,以避免复制整个结构体。
在Go中,结构体是一种非常常见的数据类型,我们经常需要将结构体作为函数参数传递,或者将结构体作为函数的返回值。
如果结构体很大,传递结构体的值将占用大量内存,并且会带来性能问题。在这种情况下,最好通过指针传递结构体,因为指针只是一个指向内存中的位置的引用,而不是复制整个结构体。这将减少内存的使用,并提高程序的性能。
例如,考虑以下结构体类型:
type Person struct {
Name string
Age int
...
}
如果我们需要在函数中修改一个非常大的Person对象,最好使用指针来传递它,以避免复制整个结构体:
func updatePerson(p *Person) {
p.Age = 30
...
}
func main() {
person := &Person{Name: "John", Age: 25, ...}
updatePerson(person)
...
}
在这个例子中,我们将指向Person结构体的指针传递给函数updatePerson
,这将避免复制整个结构体,并且允许函数修改原始对象的值。
6. 结构体的字段可以使用标签(tag)进行注释。标签是在字段后面用反引号括起来的字符串,可以用于给字段提供元数据信息。
下面是一个使用结构体标签的简单示例,其中使用标签为结构体中的字段提供了名称和其他元数据信息:
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string `json:"name" db:"full_name"`
Age int `json:"age" db:"age"`
Address string `json:"address,omitempty" db:"address"`
}
func main() {
p := Person{
Name: "John",
Age: 30,
Address: "123 Main St",
}
t := reflect.TypeOf(p)
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
fmt.Printf("%s: %s\n", field.Tag.Get("json"), field.Tag.Get("db"))
}
}
在上面的示例中,我们定义了一个名为 Person
的结构体,该结构体有三个字段:Name
、Age
和 Address
。每个字段都有一个标签,分别是 json
和 db
。在 main
函数中,我们创建了一个 Person
实例,并使用反射获取结构体的类型信息。然后,我们遍历结构体中的字段,使用 Tag.Get
方法获取每个字段的 json
和 db
标签,并打印出来。输出结果如下:
name: full_name
age: age
address: address,omitempty
从输出结果可以看出,我们可以使用标签为结构体中的字段提供元数据信息,这些元数据信息可以在编写代码时使用,比如用于序列化和反序列化、ORM 框架等。
7. 如果结构体的字段名以大写字母开头,则表示该字段是公共字段,可以在其他包中访问。如果字段名以小写字母开头,则表示该字段是私有字段,只能在同一个包中访问。
下面是一个简单的demo,其中Person
结构体有一个公共字段Name
和一个私有字段age
:
package main
import "fmt"
type Person struct {
Name string // 公共字段
age int // 私有字段
}
func main() {
p := Person{Name: "John", age: 30}
fmt.Println(p.Name) // 可以访问公共字段
// fmt.Println(p.age) // 无法访问私有字段
}
可以看到,我们可以在main
包中访问Person
结构体的公共字段Name
,但无法访问其私有字段age
。如果我们取消注释fmt.Println(p.age)
,编译器就会报错。
欢迎关注公众号上海php自学中心,一起交流。