Go学习之——struct 进阶
匿名字段
正经的结构定义
type person struct{
name string
age int
}
func main(){
p1 = person{
name: "内裤外穿的人",
age: 10000,
}
fmt.Println("%v\n", p1)
fmt.Println( p1.name)
fmt.Println( p1.age)
}
匿名字段的结构定义
type person struct{
string
int
}
func main(){
p1 = person{
"内裤外穿的人",
10000,
}
fmt.Println("%v\n", p1)
fmt.Println( p1.string) //匿名字段 用类型名代替字段名来获取字段值
fmt.Println( p1.int)
}
匿名字段与具名字段同时使用
type person struct{
name string
string
int
}
func main(){
p1 := person{
"内裤外穿的人",
"超人",
10000,
}
fmt.Printf("%v\n", p1)
fmt.Println( p1.name)
fmt.Println( p1.string) //匿名字段 用类型名代替字段名来获取字段值
fmt.Println( p1.int)
}
匿名结构体定义的注意点:
- 匿名结构体,在使用的时候,要用类型名代替字段名来使用.
- 不能出现两个相同类型的字段
- 具名字段与匿名字段可以同时使用
结构体的方法
结构体的方法首先是一个函数,其特点是:
- 函数定义的时候,在函数名前加一个结构体的类型的参数
- 结构体类型的变量可以直接用.函数名的方法来调用
- 结构体变量是一个值类型的变量,如果在结构体方法里想要改变结构体字段的值,要使用结构体指针做为结构体方法的参数
type person struct {
name string
string
int
}
// 这个方法,不能改变结构体的字段值
func (p person) speak() {
p.int ++ //这个方法对原结构体是无效的
fmt.Println("哈哈哈~~~")
}
func main() {
p1 := person{
"内裤外穿的人",
"超人",
10000,
}
fmt.Println(p1.int)
p1.speak()
fmt.Println(p1.int)
}
输出内容如下:
10000
哈哈哈~~~
10000
为了改变原结构体的字段值:
type person struct {
name string
string
int
}
// 这个方法,不能改变结构体的字段值
func (p *person) speak() {
p.int ++ //这个方法对原结构体是无效的
fmt.Println("哈哈哈~~~")
}
func main() {
p1 := person{
"内裤外穿的人",
"超人",
10000,
}
fmt.Println(p1.int)
p1.speak()
fmt.Println(p1.int)
}
输出内容如下:
10000
哈哈哈~~~
10001
说明:
- 结构体方法本质是一个函数
- 结构体方法的调用就是结构体类型的变量.函数名
- 结构体方法如果要修改结构的属性值,要传入指针型变量
- 如果一个结构体有多个方法,这些方法最好统一结构:都用传值 或 都用传指针
结构体复合
这是正常的复合
type person struct{
name string
age int
addr address
}
type address struct{
city string
}
func main(){
p1 := person{
name: "张三",
age: 20,
addr: address{
city:"浙江",
},
}
fmt.Printf("%v\n", p1)
fmt.Println(p1.addr.city)
}
这种方法,如果想要调用city的值,需要写的一长串.
如果能够像调用直接字段一样调用内层结构体的字段的话,会更加方便.
因此,改进如下
type person struct{
name string
age int
address
}
type address struct{
city string
}
func main(){
p1 := person{
name: "张三",
age: 20,
address: address{
//匿名字段的初始用,直接用类型名作为字段用来赋值
city:"浙江",
},
}
fmt.Printf("%v\n", p1)
fmt.Println(p1.address.city) //匿名字段的常规调用方法
fmt.Println(p1.city) //优化后的可以直接调用内层结构体的方法
}
将内层结构体 设置为匿名字段,这样,外层结构体变量就可以直接 调用内层结构的字段,像调用自己的字段一样了.
type person struct {
name string
age int
city string
address
}
type address struct {
city string
}
func main() {
p1 := person{
name: "张三",
age: 20,
city: "北京",
address: address{
city: "浙江",
},
}
fmt.Printf("%v\n", p1)
fmt.Println(p1.address.city) //匿名字段的常规调用方法
fmt.Println(p1.city) //优化后的可以直接调用内层结构体的方法
}
如上代码输出:
{张三 20 北京 {浙江}}
浙江
北京
可以看到,直接调用city字段的时候,显示的是外层的结构体自带的字段.而不是内层结构体的字段值.
结论:
当外层结构体与内层结构体拥有相同的字段名时,直接调用字段名,获取到的是外层结构体的字段值.
即查找逻辑是由外而内的.
结构体的方法继承
package main
import "fmt"
type person struct{
}
type student struct{
}
func (p person) speak() {
fmt.Println("会说话的人")
}
func main() {
p1 := person{
}
p1.speak()
s1 := student{
}
s1.speak()
}
编译的时候输出如下错误:
.\main.go:17:4: s1.speak undefined (type student has no field or method speak)
改进如下:
type person struct{
}
type student struct {
person //匿名一个结构体字段. 这样,可以直接调用内层结构体的字段与方法.从而达成类似继承的效果
}
func (p person) speak() {
fmt.Println("会说话的人")
}
func main() {
p1 := person{
}
p1.speak()
s1 := student{
}
s1.speak()
}