Go 语言程序设计——面向对象编程(4)

接口(2)

  • 一个非空接口自身并没有什么用处,为了让它发挥作用,我们必须创建一些自定义的类型,其中定义了一些接口所需的方法
  • 两个自定义类型的例子:
type StringPair struct { first, second string }

func (pair *StringPair) Exchange() {
  pair.first, pair.second = pair.second, pair.first
}

type Point [2]int
func (point *Point) Exchange() { point[0], point[1] = point[1], point[0] }
  • 方法的接收者声明为指向其类型的指针,以便我们可以修改调用该方法的(指针所指向的)值
  • 我们完成一个满足签名 String() string 的方法:
func (pair StringPair) String() string {
  return fmt.Sprintf("%q + %q", pair.first, pair.second)
}
  • 通常而言,除了小数据外,我们更倾向于使用指针接收者,因为传指针比传值更高效

接口嵌入

  • 接口可以嵌入其他接口,其效果与在接口中直接被嵌入接口的方法一样,例子:
type LowerCaser interface {
  LowerCase()
}

type UpperCaser interface {
  UpperCase()
}

type LowerUpperCaser interface {
  LowerCaser
  UpperCaser
}
  • LowerCaser 接口声明了一个方法 LowerCase(),它不接受参数,也没有返回值,UpperCaser 接口也类似
  • LowerUpperCaser 接口则将这两个接口嵌套进来,如果要满足它,这需要定义 LowerCase()UpperCase()
  • 嵌入可能看起来没多大的优势,但是如果需要添加两个接口添加额外的方法,例子:
type FixCaser interface {
  FixCase()
}
type ChangeCaser interface {
  LowerUpperCaser
  FixCaser
}
  • 我们可以得到一个分等级的嵌套接口,如图:


    Caser接口、类型和示例图
  • 这些接口并没有多大的用处,我们需要定义具体的类型来实现它们:

func (part *Part) FixCase() {
  part.Name = fixCase(part.Name)
}

func fixCase(s string) string {
  var chars []rune
  upper := true
  for _, char := range s {
    if upper {
      char = unicode.ToUpper(char)
    } else {
      char = unicode.ToLower(char)
    }
    chars = append(chars, char)
    upper = unicode.IsSpace(char) || unicode.Is(unicode.Hyphen, char)
  }
  return string(chars)
}

func (pair *StringPair) UpperCase() {
  pair.first = strings.ToUpper(pair.first)
  pair.second = strings.ToUpper(pair.second)
}

func (pair *StringPair) FixCase() {
  pair.first = fixCase(pair.first)
  pair.second = fixCase(pair.second)
}
  • 接口的灵活性的另一方面是,它们可以在事后创建,例子:
type IsValider interface {
  IsValid() bool
}

if thing, ok := x.(IsValider); ok {
  if !thing.IsValid(){
    reportInvalid(thing)
  } else {
    //...处理有效的thing...
  }
}
  • 创建了接口之后,我们可以检查任意自定义类型看它是否提供 IsValid() bool 方法
  • 接口提供了一种高度抽象的机制,当某些函数或者方法只关心该传入的值能完成使命工作,而不关心该值的实际类型,接口就允许我们声明一个方法的集合

推荐阅读更多精彩内容