Golang

关注公众号 jb51net

关闭
首页 > 脚本专栏 > Golang > Go Interfacs接口

Go Interface接口初学者手册

作者:海上明月A

这篇文章主要为大家介绍了Go Interface接口的基础用法实例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

Interface接口类型实现

接口是一组方法签名。如果一个类型在其上定义了给定接口的所有方法,则该类型 "实现" 了该接口。

在以下示例中,“形状” 必须能够返回其面积和周长。rect 和 circle 都满足该接口。

type shape interface {
  area() float64
  perimeter() float64
}
type rect struct {
    width, height float64
}
func (r rect) area() float64 {
    return r.width * r.height
}
func (r rect) perimeter() float64 {
    return 2*r.width + 2*r.height
}
type circle struct {
    radius float64
}
func (c circle) area() float64 {
    return math.Pi * c.radius * c.radius
}
func (c circle) perimeter() float64 {
    return 2 * math.Pi * c.radius
}

当一个类型实现一个接口时,它可以被用作该接口类型。

接口的实现是隐式的。

类型从不声明它实现了给定的接口。如果接口存在,并且类型定义了适当的方法,那么该类型会自动满足该接口。

Multiple Interfaces

在Go中,一个类型可以实现任意数量的接口。例如,空接口 interface{} 总是被每种类型实现,因为它没有要求。

Naming interface args

考虑以下接口:

type Copier interface {
  Copy(string, string) int
}

根据仅有的代码,你能推断出应该将什么类型的字符串传递给 Copy 函数吗?

我们知道函数签名期望两个字符串类型,但它们是什么?文件名?URL?原始字符串数据?另外,返回的那个整数到底是什么?

让我们添加一些有名的参数和返回数据,使其更清晰。

type Copier interface {
  Copy(sourceFile string, destinationFile string) (bytesCopied int)
}

好多了。现在我们可以看到期望是什么了。第一个参数是 sourceFile,第二个参数是 destinationFile,并返回了一个整数 bytesCopied

Type Assertions in Go

在Go中使用接口时,偶尔需要访问接口值的底层类型。您可以使用类型断言将接口转换为其底层类型。

type shape interface {
  area() float64
}
type circle struct {
  radius float64
}
// "c" is a new circle cast from "s"
// which is an instance of a shape.
// "ok" is a bool that is true if s was a circle
// or false if s isn't a circle
c, ok := s.(circle)
if !ok {
  // s wasn't a circle
  log.Fatal("s is not a circle")
}
radius := c.radius

Type Switches in Go

类型开关使得在一系列中执行多个类型断言变得很容易。

类型开关类似于常规的开关语句,但是情况指定的是类型而不是值。

func printNumericValue(num interface{}) {
  switch v := num.(type) {
  case int:
    fmt.Printf("%T\n", v)
  case string:
    fmt.Printf("%T\n", v)
  default:
    fmt.Printf("%T\n", v)
  }
}
func main() {
  printNumericValue(1)
  // prints "int"
  printNumericValue("1")
  // prints "string"
  printNumericValue(struct{}{})
  // prints "struct {}"
}

fmt.Printf("%T\n", v) 打印变量的类型。

Clean Interfaces

编写清晰的接口很难。坦率地说,每当在代码中处理抽象概念时,如果不小心,简单的事情很快就会变得复杂。让我们回顾一些保持接口清晰的经验法则。

 Keep Interfaces Small

如果你从这篇文章中只记住一点建议,那就是:保持接口的小巧!接口的目的是定义准确表示一个想法或概念所需的最小行为。

以下是标准 HTTP 包中的一个较大接口的示例,它很好地演示了定义最小行为的概念:

type File interface {
    io.Closer
    io.Reader
    io.Seeker
    Readdir(count int) ([]os.FileInfo, error)
    Stat() (os.FileInfo, error)
}

满足接口行为的任何类型都可以被 HTTP 包视为 File。这很方便,因为 HTTP 包不需要知道它处理的是磁盘上的文件,网络缓冲区还是简单的 []byte。

 Interfaces Should Have No Knowledge of Satisfying Types

接口应该定义其他类型需要满足的条件以成为该接口的成员。它们在设计时不应该知道任何恰好满足该接口的类型。

例如,假设我们正在构建一个描述定义汽车所需组件的接口。

type car interface {
  Color() string
  Speed() int
  IsFiretruck() bool
}

Color() 和 Speed() 完全有道理,它们是限定在汽车范围内的方法。IsFiretruck() 是一个反模式。我们强制所有汽车声明它们是否是消防车。为了使这种模式有任何意义,我们需要一个可能的子类型清单。IsPickup()IsSedan()IsTank()... 这会无休止地扩展。

相反,开发人员应该依赖于类型断言的本机功能,在给定汽车接口的实例时推导出底层类型。或者,如果需要子接口,可以这样定义:

type firetruck interface {
  car
  HoseLength() int
}

这个接口继承了 car 所需的方法,并添加了一个额外的必需方法,使车辆成为消防车。

Interfaces Are Not Classes

接口不是类,它们更加轻量。

接口没有构造函数或析构函数,不要求创建或销毁数据。

接口在本质上不是层次结构,尽管有语法糖可以创建接口,这些接口碰巧是其他接口的超集。

接口定义了函数签名,但不定义底层行为。创建接口通常不会在结构方法方,使代码更加干燥。例如,如果有五种类型满足 fmt.Stringer 接口,它们都需要有自己版本的 String() 函数。

以上就是Go Interfaces接口初学者手册的详细内容,更多关于Go Interfaces接口的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文