摘要:Go中的Anonymous fields使得我们可以缩写点语法,同时也允许我们使用compositions来给一个方法添加类型
转自: Anonymous fields in Go
Anonymous fields in Go structures allow us to shortcut dot notation as well as allow us to use compositions to add methods to a type.
Shortcutting the dot notation
For example if we have something like this
type A struct {
X int
Y int
}
type B struct {
Z int
}
type C struct {
AValue A
BValue B
}
then to access the field X on AValue we’d write code like this
c := C {}
c.AValue.X = 1
Changing the C struct fields to anonymous (i.e. removing the field name) like this
type C struct {
A
B
}
allows us to reduce the use of the dot notation and access X on A as if it was a field within the C struct itself, i.e.
c := C {}
c.X = 1
Okay, but what if B struct now replaced the Z field name with X, i.e.
type A struct {
X int
Y int
}
type B struct {
X int
}
We now have a situation where both A and B have the same field name, well we can still use anonymous fields, but we’re back to using more dot notation again to get around the obvious field name conflict, i.e.
c := C {}
c.A.X = 1
c.B.X = 2
Initializers do not support shortcutting
Unfortunately we not get the advantage of the anonymous fields with the initializer syntax, i.e. We must specify the A and B structs like this
c := C{ A : A{2, 4}, B : B { 12 }}
// or
c := C{ A : A{X : 2, Y : 4}, B : B { Z: 12 }}
// but this doesn't compile
c := C{ X : 2, Y : 4, Z : 12 }
// nor does this compile
c := C{ A.X : 2, A.Y = 3, B.Z : 12 }
Composition
More powerful than the synaptic sugar of embedded/anonymous fields, we can also use composition to increase the methods available on the struct C. For example let’s now add a method to the A type which allows us to move our X, Y point
func (a *A) Move(amount int) {
a.X += amount
a.Y += amount
}
Now we can call the method on the previously declared c
variable like this
c.Move(10)
We can also create further methods via a composition pattern on type C if we want using empty types, let’s assume we have type D and extend the composition of type C
type D struct {}
type C struct {
A
B
D
}
now we can add methods to D and ofcourse they’ll be available as part of C. So for example, maybe D acts as a receiver for methods that serialize data to JSON, now our C type will also appear to have those methods.