我们可以使用切片来保存一组数据。
使用映射来保存一组键值。
但是这两种都只能保存一种类型,如果需要保存一种以上类型的数据,如保存学生的基本信息,包括学生的年龄(string 类型)和成绩(float 类型)等,就需要用到 struct
。
定义 struct
var myStruct struct {
number float64
word string
toggle bool
}
fmt.Printf("%#v\n", myStruct)
// 输入如下:
//struct { number float64; word string; toggle bool }{number:0, word:"", toggle:false}
当我们调用 Printf 中的%#v 的时候,它将 myStruct 中的值作为 struct 字面量打印。
使用点运算符对 struct 进行赋值和检索
myStruct.number = 3.14
myStruct.word = "Hello"
myStruct.toggle = true
fmt.Println(myStruct.number, myStruct.word, myStruct.toggle)
定义 struct 类型
可以使用 type 关键字定义 struct 类型。
type car struct {
// fields
name string
topSpeed float64
}
func main() {
byd := car{}
byd.name = "宋"
byd.topSpeed = 220
fmt.Println(byd)
changCheng := car{
name: "哈佛H6",
topSpeed: 200,
}
fmt.Println(changCheng)
}
}
// 输出
{宋 220}
{哈佛H5 200}
就像变量,类型定义可以被放在一个函数中。但是把它的作用域限定在该函数块中,意味着你不能在函数外面使用。所以类型经常定义在函数外的包级别。
使用函数修改 struct
Go 是一个按值传递的语言,意味着函数调用时接收的是一个参数的拷贝。
如果函数修改了参数值,它修改的只是拷贝,而不是原始值。
type Person struct {
name string
age int
}
func changeName(p Person) {
p.name = "Tom"
}
func main() {
person := Person{
name: "Jack",
age: 18,
}
changeName(person)
fmt.Println(person) // {Jack 18}
}
解决方案是修改函数,使它能够接收一个值的指针来代替直接接收值。
当调用这个函数时,我们使用取址运算符(&)
来传送我们需要更新的值的指针。然后在函数内部,我们使用*
来更新指针指向的值。
我们可以使用指针来让函数也能更新 struct。
type Person struct {
name string
age int
}
func changeName(p *Person) {
p.name = "Tom"
}
func main() {
person := Person{
name: "Jack",
age: 18,
}
changeName(&person)
fmt.Println(person) //{Tom 18}
}
通过指针访问 struct 的字段
我们可以使用*
运算符(就像我们调用取值运算符)来获取指针指向的值。
但是当我们需要对指向struct的指针
直接使用*运算符
, 是无法工作的。
type myStruct struct {
myField int
}
func main() {
var structVal myStruct
structVal.myField = 5
var point *myStruct = &structVal
fmt.Println(point.myField) // ok 输出:5
// fmt.Println(*point.myField)
// error: cannot indirect point.myField (variable of type int)
}
正确的使用方式是,添加一个括号:
fmt.Println((*point).myField) // ok 输出:5
由于添加括号比较麻烦,因此go 运行时会自动处理,不管是调用,或是赋值,都可以直接使用
point.myField
即可