我熟悉的一个事实是,在Go中,接口定义了功能而不是数据。您将一组方法放到一个接口中,但是您无法指定任何实现该接口的任何字段。转到界面字段
例如:
// Interface
type Giver interface {
Give() int64
}
// One implementation
type FiveGiver struct {}
func (fg *FiveGiver) Give() int64 {
return 5
}
// Another implementation
type VarGiver struct {
number int64
}
func (vg *VarGiver) Give() int64 {
return vg.number
}
现在我们可以使用接口和它的实现:
// A function that uses the interface
func GetSomething(aGiver Giver) {
fmt.Println("The Giver gives: ", aGiver.Give())
}
// Bring it all together
func main() {
fg := &FiveGiver{}
vg := &VarGiver{3}
GetSomething(fg)
GetSomething(vg)
}
/*
Resulting output:
5
3
*/
现在,你不能做的是这样的:
type Person interface {
Name string
Age int64
}
type Bob struct implements Person { // Not Go syntax!
...
}
func PrintName(aPerson Person) {
fmt.Println("Person's name is: ", aPerson.Name)
}
func main() {
b := &Bob{"Bob", 23}
PrintName(b)
}
但是,在玩弄接口和嵌入结构,我发现了一种方式来做到这一点,在时尚之后:
type PersonProvider interface {
GetPerson() *Person
}
type Person struct {
Name string
Age int64
}
func (p *Person) GetPerson() *Person {
return p
}
type Bob struct {
FavoriteNumber int64
Person
}
由于嵌入式结构,鲍勃拥有一切人有。它还实现了PersonProvider接口,所以我们可以将Bob传递到设计为使用该接口的函数中。
func DoBirthday(pp PersonProvider) {
pers := pp.GetPerson()
pers.Age += 1
}
func SayHi(pp PersonProvider) {
fmt.Printf("Hello, %v!\r", pp.GetPerson().Name)
}
func main() {
b := &Bob{
5,
Person{"Bob", 23},
}
DoBirthday(b)
SayHi(b)
fmt.Printf("You're %v years old now!", b.Age)
}
Here is a Go Playground说明上面的代码。
使用这种方法,我可以创建一个定义数据而不是行为的接口,并且可以通过嵌入数据来实现任何结构。您可以定义明确与该嵌入数据交互的函数,但不知道外部结构的性质。并且在编译时检查所有内容! (只有这样,你可以搞砸了,我所看到的,将是嵌入接口PersonProvider
在Bob
,而不是具体Person
这将编译并在运行时失败。)
现在,这里是我的问题:是这样的一个整洁的技巧,还是我应该以不同的方式做?
“我可以制作一个定义数据而不是行为的界面”。我认为你有一个返回数据的行为。 – jmaloney 2014-09-24 22:22:08
我会写一个答案;我认为如果你需要它并且知道后果就没有问题,但是会有后果,我不会一直这么做。 – twotwotwo 2014-09-24 22:22:58
@jmaloney我认为你是对的,如果你想清楚地看看它。但总的来说,在我展示的不同部分中,语义变成“这个函数接受任何结构中有___的结构”。至少,这是我的意图。 – 2014-09-25 00:11:39