【问题标题】:How to deal with repetitiveness and flexibility when implementing Go interfaces?实现 Go 接口时如何处理重复性和灵活性?
【发布时间】:2021-05-09 19:10:11
【问题描述】:

我有一个使用如下结构的项目:

type I interface {
  GetName() string
  DoSomething()
}

//
// A implements I
//
type A struct {
    Name  string
}

func (a *A) GetName() string {
  return a.Name
}

func (a *A) DoSomething() {
  ...do something
}

//
// B implements I
//
type B struct {
    Name  string
}

func (b *B) GetName() string {
  return b.Name
}

func (b *B) DoSomething() {
  ...do something
}

func (b *B) DoSomethingElse() {
  ...do something else
}

//
// Both
//
func UseAorB(T I) {
  name := T.GetName()...
}
  1. 在采用接口 I 的函数中调用时,使用 GetName 是从结构 A 或 B 获取名称字段的最佳方式吗?
  2. 我是否必须每次都为要实现接口的每个事物重新定义 DoSomething?或者如果 DoSomething 每次我都可以定义一次时都相同,是否有更好的方法来做到这一点?
  3. 结构 B 有一个接口未定义的方法 (DoSomethingElse)。我是否需要使用反射才能将 Struct B 传递给使用接口 I 调用 DoSomethingElse 的函数?还是应该定义一个包含此方法的新接口?

我想提高我的代码质量并编写一个可靠的库,但我不得不说这感觉就像我在与语言作斗争并使我的生活变得更加困难。

【问题讨论】:

标签: go


【解决方案1】:
  1. 是的,GetName() 是这样做的好方法

  2. 如果你有类似的方法实现,你通常可以将它移动到一个公共结构并嵌入它:

    type Common struct {}
    
    func (c Common) DoSomething() {...}
    
    type A struct {
       Common
       Stuff
    }
    
    type B struct {
       Common
       Other stuff
    }
    

    以上,AB 都有DoSomething 方法,它们共享实现

  3. 不要使用反射。有两种方式:

    1. 使用类型断言:

      func f(in I) {
         if b, ok:=in.(B); ok {
            // b is of type B, so:
            b.DoSomethingElse()
         }
      }
      
    1. 使用接口和类型断言:

      type DoesSometingElse interface {
         DoSomethingElse()
      }
      
      func f(in I) {
         if x, ok:=in.(DoesSomethingElse); ok{
            x.DoSomethingElse()
         }
      }
      

如果您觉得自己在与该语言作斗争,那么您的建模不正确,或者您不知道用该语言做某事的正确方法。在所有语言中都有好的和坏的做事方式,而且很多时候每种语言都是不同的。如果您是从另一种语言开始使用 Go,您应该首先停止尝试用另一种语言思考并翻译成 Go,并尝试单独使用 Go。

【讨论】:

  • 绝对优秀。嵌入结构是在多个实现相同接口的结构实例之间共享通用功能的最佳方式。
猜你喜欢
  • 2020-03-20
  • 1970-01-01
  • 1970-01-01
  • 2017-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-18
  • 1970-01-01
相关资源
最近更新 更多