用嵌入字段实现代码重用
对数据结构加锁机制的常用方式,是嵌入一个sync.Mutex或sync.RWMutex。
type Foo struct {
sync.Mutex
// ... other fields
}
f := new(Foo)
f.Lock()
// ... operations
f.Unlock()
Foo嵌入了sync.Mutex,所以可以在Foo结构上直接调用Lock和Unlock方法。 但这不是个仅限于此的语法糖,Foo实际已经实现了sync.Locker接口,就好像是Foo自己定义了Lock和Unlock方法一样。 Foo结构可以用于任何需要sync.Locker的地方,例如
condition := sync.NewCond(new(Foo))
这就类似于接口的默认实现(default implementation)。实现接口时,只需要嵌入一个实现了此接口的类型, 而不需要重新实现一遍方法,或者使用命名字段再包装出接口所需的方法。
当然这个和真正的默认实现机制是有区别的,方法里如果需要引用被嵌入的类型的字段,须要在构造嵌入字段时显式传入。 例如这个接口
type Named interface {
PrintName()
}
要提供一个Named接口的可以嵌入的实现NamedImpl,可以有以下的方法。其一
type Named interface {
PrintName()
GetName() string
}
type NamedImpl struct {
named Named
}
func (n NamedImpl) PrintName() {
fmt.Printf("name is %s\n", n.named.GetName())
}
type Foo struct {
NamedImpl
Name string
}
func (f Foo) GetName() string {
return f.Name
}
func main() {
var f Foo
f.Name = "foo"
f.NamedImpl = NamedImpl{f}
f.PrintName()
}
给Named接口增加一个GetName方法。虽然感觉有点多余但也算可行。
其二,不增加接口方法,只传需要的数据的引用
type Named interface {
PrintName()
}
type NamedImpl struct {
name *string
}
func (n NamedImpl) PrintName() {
fmt.Printf("name is %s\n", *n.name)
}
type Foo struct {
NamedImpl
Name string
}
func main() {
var f Foo
f.Name = "foo"
f.NamedImpl = NamedImpl{&f.Name}
f.PrintName()
}
其三,不使用引用,而是嵌入一个closure以获得所需数据
type Named interface {
PrintName()
}
type NamedImpl func() string
func (n NamedImpl) PrintName() {
fmt.Printf("name is %s\n", n())
}
type Foo struct {
NamedImpl
Name string
}
func main() {
var f Foo
f.Name = "foo"
f.NamedImpl = func() string { return f.Name }
f.PrintName()
}
以上例子中,其他类型要实现Named接口,可以不实现PrintName方法,而是嵌入一个NamedImpl。
func main() {
b := struct {
NamedImpl
name string
}{}
b.name = "bar"
b.NamedImpl = func() string { return b.name }
b.PrintName()
}
这就实现了代码的重用。
2014-08-28
comments powered by Disqus