Golang初级系列教程-结构体匿名字段-Anonymous fields in structs

Golang初级系列教程-结构体匿名字段-Anonymous fields in structs

Go 结构体中支持匿名字段。下面的几个例子中,会展示如何构造以及这种用法的好处。

下面的代码中,定义了结构体 Kitchen,包含字段 numOfPlates。另一个结构体 House,包含 Kitchen 的一个实例,但是没有变量名——即匿名。

package main

import "fmt"

type Kitchen struct {
    numOfPlates int
}

type House struct {
    Kitchen //anonymous field
    numOfRooms int
}

func main() {
    h := House{Kitchen{10}, 3} //to initialize you have to use composed type name.
    fmt.Println("House h has this many rooms:", h.numOfRooms) //numOfRooms is a field of House
    fmt.Println("House h has this many plates:", h.numOfPlates) //numOfPlates is a field of anonymous field Kitchen, so it can be referred to like a field of House
    fmt.Println("The Kitchen contents of this house are:", h.Kitchen) //we can refer to the embedded struct in its entirety by referring to the name of the struct type
}
House h has this many rooms: 3
House h has this many plates: 10
The Kitchen contents of this house are: {10}

首先需要强调的一点是,由于 KitchenHouse 的匿名字段,House 可以访问 Kitchen 的属性,就如同这些属性是 House 本身的一样。为了说明这一点,让我们同 Java 代码做一个对比。

public class Kitchen {
    public int numOfPlates;
}

public class House {
    public Kitchen kitchen;
}

//and in main
public static void main(String[] args) {
    House h = new House();
    h.kitchen.numOfPlates = 10; //referred as a sub field item.
}

其次,匿名字段通过其类型名也可以访问。所以,对于上面的的例子,可以通过 h.kitchen 访问,这时打印盘子个数应该写为 fmt.Println(h.Kitchen.numOfPlates)

第三点,定义时,必须使用类型名,如同上面所示 h := House{Kitchen{10}, 3}。如果不写上类型和其对应的 {},如同下面的两种定义方式都会产生编译错误,h := House{{10}, 3}h := House{10, 3}

匿名类型命名冲突

当匿名字段包含相同的字段命名或者外围结构体含有和匿名结构相同的字段名时,程序会如何运行?当外围结构体含有和匿名结构相同的字段时,默认访问外围结构体的字段。下面的代码中,kitchenHouse 都有个字段名为 numOfLamps,由于 House 包含 kitchen ,所以 HousenumOfLamps 会覆盖 kitchen 的。如果想访问 kitchennumOfLamps ,则需要通过使用类型名 h.Kitchen.numOfLamps

package main

import "fmt"

type Kitchen struct {
    numOfLamps int
}

type House struct {
    Kitchen
    numOfLamps int
}

func main() {
    h := House{Kitchen{2}, 10} //kitchen has 2 lamps, and the House has a total of 10 lamps
    fmt.Println("House h has this many lamps:", h.numOfLamps) //this is ok - the outer House's numOfLamps hides the other one.  Output is 10.
    fmt.Println("The Kitchen in house h has this many lamps:", h.Kitchen.numOfLamps) //we can still reach the number of lamps in the kitchen by using the type name h.Kitchen
}
House h has this many lamps: 10
The Kitchen in house h has this many lamps: 2

所以,当结构体不同级组合遇到命名冲突时,存在字段的解析规则。但是,对于同一级的结构体字段命名冲突,程序无法完成解析——需要自行解决。

下面代码中,KitchenBedroom 都包含 numOfLamps 字段,并且都是 House 的匿名字段。当访问 House.numOfLamps 时,Go 编译器不知道是访问哪个,进而抛出错误。

package main

import "fmt"

type Kitchen struct {
    numOfLamps int
}

type Bedroom struct {
    numOfLamps int
}

type House struct {
    Kitchen
    Bedroom
}

func main() {
    h := House{Kitchen{2}, Bedroom{3}} //kitchen has 2 lamps, Bedroom has 3 lamps
    fmt.Println("Ambiguous number of lamps:", h.numOfLamps) //this is an error due to ambiguousness - is it Kitchen.numOfLamps or Bedroom.numOfLamps
}
8g -o _go_.8 structs2.go
structs2.go:20: ambiguous DOT reference House.numOfLamps
make: *** [_go_.8] Error 1

只能通过使用类型名的方式进行访问,如下面代码所示。

package main

import "fmt"

type Kitchen struct {
    numOfLamps int
}

type Bedroom struct {
    numOfLamps int
}

type House struct {
    Kitchen
    Bedroom
}

func main() {
    h := House{Kitchen{2}, Bedroom{3}}
    fmt.Println("House h has this many lamps:", h.Kitchen.numOfLamps + h.Bedroom.numOfLamps) //refer to fields via type name
}
House h has this many lamps: 5

Golang一种神奇的语言,让我们一起进步

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值