golang:annoymous field in a struct

http://golangtutorials.blogspot.com/2011/06/anonymous-fields-in-structs-like-object.html

GoLang Tutorials

 

Sunday, June 5, 2011

Anonymous fields in structs - like object composition

Other topics in this series - Table of Contents


Go allows you to define a struct that has fields but with no variable names. These fields are called anonymous fields. Let’s do a few examples to find out what they are and how they will be useful.

In the below example, we have defined a Kitchen struct, which only contains the number of plates as a field. We define another field called House, which contains an instance of Kitchen as a field - but it is an anonymous field, because we have not given a variable name for it.

Full code

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}


The first important thing to note is that since we have defined Kitchen to be an anonymous field, it allows us to access its members as if they were members of the encompassing class. In comparison, if you were using a language like Java, you would have to do:

Partial Java code

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.
}


The second important thing to note is that the composed field is still available to be accessed, but by its type name. So in this case the anonymous field for Kitchen has to be accessed as h.Kitchen. If you want to print the number of plates in the kitchen, then do this: fmt.Println(h.Kitchen.numOfPlates).

And the third important thing to note is how we had to use the type name when initializing the values as we did: h := House{Kitchen{10}, 3}. It is necessary here that you state the type name and provide its values within the corresponding curly braces. So h := House{{10}, 3} and h := House{10, 3} will cause compilation errors.
 

Anonymous fields - when naming conflicts arise

What happens when more than one of the composed structs or the composing struct has the same field name. If there is a field in an outer struct with the same name as a field in an inner anonymous struct, then the outer one is accessible by default. In the below example, both the Kitchen and the House has a numOfLamps field, but since House is the outer struct, its numOfLamps hides Kitchen’s. If you still require to access the Kitchen’s numOfLamps, that is possible by referring to it via the type name: h.Kitchen.numOfLamps.

Full code

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


So there is a rule on field resolution when the same field occurs at different levels of composition. But there is no rule when the fields are at the same level of composition - which means that when it occurs you need to resolve it yourself.

In the code below, both the Kitchen and the Bedroom have a field numOfLamps, and both are available as an anonymous field within House. Now if we referred to House.numOfLamps, the Go compiler cannot resolve whether you are referring to the numOfLamps within Kitchen or that within Bedroom and it throws an error.

Full file: structs2.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
}


Compiler error

8g -o _go_.8 structs2.go
structs2.go:20: ambiguous DOT reference House.numOfLamps
make: *** [_go_.8] Error 1


To resolve this, you will have to refer to the required fields explicitly via the type name of the anonymous field. In the corrected example below, we’ve summed up the number of lamps in the kitchen and the bedroom by referring to the number of lamps in it via its type name.
 

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值