【问题标题】:What are some examples of Go interfaces?Go 接口有哪些例子?
【发布时间】:2010-12-16 14:54:00
【问题描述】:

我找到了关于 Go 的 an interesting blog post

我正在尝试理解接口的概念,但我发现从博客文章中的代码片段很难做到这一点,而从the language specification 几乎不可能做到。

谁能指出 Go 接口在工作程序中的简单示例?

【问题讨论】:

标签: go


【解决方案1】:

这是一个正在进行中的学习练习,当然是良好风格的一个糟糕例子,但是here you go (spec)。

另外,作为一个更奇特的例子,我在 go-nuts 邮件列表上创建了a post,关于使用 interface{} 构建处理匿名数据的函数(在这种情况下,是“三元运算”函数):

package main
import "fmt";
func Tern(exp bool, a interface{}, b interface{}) (interface{}) {
    if exp { return a }
    return b
}
func main() {
    a := 7; b := 1;
    result := Tern(a > b, a, b);
    fmt.Printf("%d\n", result);
}

【讨论】:

  • 谢谢,我会看看你的例子。我想要一段编译代码,这样看起来不错。
  • 这里的interface{} 是什么意思?
  • "interface{}" 是一个空接口;换句话说,它匹配所有类型。将其视为“任何”值:一种编写可以对任何值进行操作的通用函数的方法。可悲的是,这里非常缺乏文档;这与“反射”包一起,为您提供了一些非常有趣的类型操作选项。
  • 我正在查看一些关于 reflect 的库代码,但最终有点困惑。它在Printf 例程中被大量使用,其中变量的类型来自变量本身。但我迷失在一个曲折的依赖迷宫中。
  • 如果interface 被替换为int,这个例子就可以正常工作。见play.golang.org/p/ww-5ma7m5IS
【解决方案2】:

教程“Interfaces in Go - Part 2: Aiding adaptable, evolutionary design ”(2012 年 1 月,来自 Sathish VJ)清楚地提到了 Go 中接口的主要优势:

Go 的接口不是 Java 或 C# 接口的变体,它们更多。
它们是大规模编程和适应性进化设计的关键

请参阅同一篇文章中关于总线的不同视角(接口)的这个示例:

package main

import "fmt"

//Go Step 1: Define your data structures
type Bus struct {
    l, b, h int
    rows, seatsPerRow int
}

//Go Step 2: Define a real world abstraction that could use the data we structure we have
type Cuboider interface {
    CubicVolume() int
}

//Go Step 3: Implement methods to work on data
func (bus Bus) CubicVolume() int {
    return bus.l *  bus.b * bus.h
}

//Go step - repeat 2 & 3 for any other interfaces
type PublicTransporter interface  {
    PassengerCapacity() int
}

func (bus Bus) PassengerCapacity() int {
    return bus.rows * bus.seatsPerRow
}

func main() {
    b := Bus{
             l:10, b:6, h:3,
             rows:10, seatsPerRow:5}

    fmt.Println("Cubic volume of bus:", b.CubicVolume())
    fmt.Println("Maximum number of passengers:", b.PassengerCapacity())
}

它似乎以数据为中心 - 首先定义您的数据,并在您进行时构建您的接口抽象。
这里的层次结构是“沿途”构建的,没有明确说明 - 根据与类型关联的方法签名,它被理解为实现特定的接口。

现在让我们假设随着时间的推移,我们的巴士的一些项目要求发生了变化 - 现在有一项新法律规定每位乘客至少应有一定的最小立方体积。
我们的总线现在必须遵守一个名为 PersonalSpaceLaw 的新接口,它不同于它已经实现的任何其他接口

//new requirement that the Bus must be compatible with
type PersonalSpaceLaw interface {
    IsCompliantWithLaw() bool
}

func (b Bus) IsCompliantWithLaw() bool {
    return (b.l * b.b * b.h) / (b.rows * b.seatsPerRow) >= 3
}

功能已被扩展,核心类或核心层次结构没有任何变化。这种实现更加简洁、易于扩展,并且可以随着项目需求的不断变化而更好地扩展。

这里是full working program in Go Playground

文章以 John Asmuth 引用的关于 Go 中接口的生产力的帖子结尾:

“事实上,我不必花时间预先设计某种类型层次结构,然后在完成之前重新排列它两到三遍。
这甚至不是很容易做到正确的事实 -
事实上我只是不必担心它并且可以继续使用实际的算法。

【讨论】:

【解决方案3】:
package main

type Stringer interface {
    String() string
}

type pie int
type pizza string

func (p pie) String() string{
    return "pie"
}

func (p pizza) String() string{
    return "pizza"
}

func main(){
    var a pie
    var b pizza
    fmt.Println(a,b) //fmt.Println() will look for Stringers and call their String() method.
}

【讨论】:

    【解决方案4】:

    扩展@Jessta 很好的例子。给出了一个在工作程序中使用 Go 接口访问 Go 标准库的简单示例。

    package main
    
    import (
        "encoding/json"
        . "fmt"
    )
    
    func main() {
        var i interface{} = c
    
        e := func() error { return c } // type error interface { Error() string}
        Println(e())                   // Hiss
    
        s := func() Stringer { return d } // type Stringer interface {String() string}
    
        // func Println(a ...interface{}) (n int, err error)
        Println(s()) // Woof
    
        d := `{"Pet":"Dog","Age":2, "Eat": "Bone"}`
        json.Unmarshal([]byte(d), &i) // func Unmarshal(data []byte, v interface{}) error
        m := i.(map[string]interface{})
        Println(m["Age"]) // 2
    }
    
    type cat string
    type dog string
    var c cat
    var d dog
    func (cat) Error() string { return "Hiss" }
    func (dog) String() string { return "Woof" }
    

    接口是 Go 最独特和最强大的功能。它们对图书馆设计有着深远的影响。它们支持真正的组件架构。主要的例子是 io.Reader 和 io.Writer,Unix 管道思想的概括。见https://talks.golang.org/2015/simplicity-is-complicated.slide

    按照惯例,错误有类型error,一个简单的内置接口。请参阅 https://golang.org/doc/effective_go.html#errorshttps://talks.golang.org/2012/splash.article。错误变量表示可以将自身描述为字符串的任何值。 func() error { return c } 致电 type error interface { Error() string}func (cat) Error() string 实现 type error interface { Error() string}。见https://blog.golang.org/error-handling-and-go

    Stringer 可以漂亮地打印自己。任何实现 String 的东西都是 Stringer。 fmt.Println 如果参数是 Stringer,则调用 String 方法。见https://talks.golang.org/2013/go4python.slide#33func() Stringer { return d } 致电 type Stringer interface {String() string}func (dog) String() string 实现 type Stringer interface {String() string}

    fmt.Println 的签名是func Println(format string, a ...interface{}) (n int, err error),也就是说它的参数(在格式字符串之后)是接口值。见https://blog.golang.org/constants。引用已编辑以匹配示例。

    标准库中关键接口的广泛使用使得将 API 链接在一起变得很容易。见https://talks.golang.org/2012/goforc.slide#46。有关更多示例,请参阅 https://talks.golang.org/2014/go4gophershttps://talks.golang.org/2014/go4gophers.slide#1

    【讨论】:

    【解决方案5】:

    Go 中接口的基本概念是,任何实现方法定义接口的对象都可以成为该接口的一部分。

    最好的例子是 Writer 界面。 Rob Pike 在 Google Tech Talk (http://www.youtube.com/watch?v=rKnDgT73v8s) 的介绍性演讲中有一个例子 - 滚动到演讲的 33:25 进行解释。

    【讨论】:

      【解决方案6】:

      Wikipedia 解释了鸭式打字并在 Go 中有一个示例。 http://en.wikipedia.org/wiki/Duck_typing

      【讨论】:

      • 截至 2018 年,Python 3 中唯一的示例
      猜你喜欢
      • 2012-12-12
      • 2019-12-23
      • 2017-05-15
      • 2022-08-24
      • 1970-01-01
      • 1970-01-01
      • 2015-02-10
      • 2011-12-23
      • 1970-01-01
      相关资源
      最近更新 更多