一些Go接口的例子有哪些?

huangapple go评论113阅读模式
英文:

What are some examples of Go interfaces?

问题

我在这篇有趣的博客文章中发现了关于Go的内容。

我正在尝试理解接口的概念,但是从博客文章中的代码片段中很难做到,从语言规范中几乎是不可能的。

有人能指出一个在工作程序中使用Go接口的简单例子吗?

英文:

I found an interesting blog post about Go.

I am trying to understand the concept of interfaces, but I find it very hard to do so from the code fragment in the blog post, and nearly impossible from the language specification.

Can anyone point out a simple example of Go's interfaces in a working program?

答案1

得分: 4

这是一个正在进行中的学习练习,当然是一个不好的代码风格的例子,但是在这里可以找到(规范)。

此外,作为一个更奇特的例子,我在go-nuts邮件列表上发表了一篇关于使用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);
}
英文:

It's a work-in-progress learning exercise, and certainly a poor example of good style, but here you go (spec).

Additionally, as a more exotic example, I made a post on the go-nuts mailing list regarding using interface{} for building functions that work with anonymous data (in this case, a "ternary operation" function):

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);
}

答案2

得分: 4

教程《Go中的接口-第2部分:帮助适应性、进化设计》(2012年1月,作者Sathish VJ)清楚地提到了Go中接口的主要优势:

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

看看同一篇文章中关于公交车的不同视角(接口)的示例:

package main

import "fmt"

//Go步骤1:定义数据结构
type Bus struct {
    l, b, h int
    rows, seatsPerRow int
}

//Go步骤2:定义一个可以使用我们已有的数据结构的真实世界抽象
type Cuboider interface {
    CubicVolume() int
}

//Go步骤3:实现用于处理数据的方法
func (bus Bus) CubicVolume() int {
    return bus.l *  bus.b * bus.h
}

//Go步骤- 为其他接口重复步骤2和3
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("公交车的体积:", b.CubicVolume())
    fmt.Println("最大乘客数:", b.PassengerCapacity())
}

> 它似乎是以数据为中心的 - 首先定义数据,然后根据需要构建接口抽象。
这里的层次结构是在“一路上”构建的,而不是明确声明的 - 根据与类型关联的方法签名,可以理解为实现了特定的接口。

> 现在假设随着时间的推移,我们公交车的一些项目需求发生了变化 - 现在有一项新法律规定每位乘客至少应有一定的最小体积。
我们的公交车现在必须遵守一个名为PersonalSpaceLaw的新接口,该接口与它已经实现的任何其他接口都不同。

//公交车必须兼容的新要求
type PersonalSpaceLaw interface {
    IsCompliantWithLaw() bool
}

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

> 功能已经扩展,而不需要对核心类或核心层次结构进行任何更改。这种实现更加清晰、易于扩展,并且可以更好地适应项目需求的变化。

这是在Go Playground中的**完整可运行程序**

文章以John Asmuth在关于Go接口的生产力线程中的引用结束:

> “事实上,我不必花时间事先设计某种类型层次结构,然后在完成之前重新排列两三次。
甚至不是因为很容易做对 -
而是因为我根本不必担心它,可以继续进行实际的算法。"

英文:

The tutorial "Interfaces in Go - Part 2: Aiding adaptable, evolutionary design " (January 2012, from Sathish VJ) mentions clearly the main advantage for interfaces in Go:

> Go's interfaces aren't a variant on Java or C# interfaces, they're much more.
They are a key to large-scale programming and adaptable, evolutionary design.

See this example, from the same article, about different perspective (interface) for a Bus:

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())
}

> It appears to be data centric - define your data first and build your interface abstractions as you go along.
Hierarchy here is kind of built 'along the way' without explicitly stating it - depending on the method signatures associated with the type, it is understood as implementing specific interfaces.

> Let us assume now that as time evolved, some of the project requirements for our Bus changed - there is now a new law that says that each passenger should at least have a certain minimum amount of cubic volume.
Our Bus now now has to adhere to a new interface called PersonalSpaceLaw which is distinct from any of the other interfaces it already implements

//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
}

> The functionality has been extended without any change to the core classes or core hierarchies. This implementation is much cleaner, easily extensible, and can scale better with the changing needs of the project's requirements.

Here is the full working program in Go Playground

The article ends with John Asmuth's quote from from the thread about the productivity of interfaces in Go:

> "It's the fact that I don't have to spend time up front designing some sort of type hierarchy and then rearranging it two or three times before I finish.
It's not even the fact that it's easy to do it right -
it's the fact that I just don't have to worry about it and can get on with the actual algorithm."

答案3

得分: 2

包 main

类型 Stringer 接口 {
String() string
}

类型 pie int
类型 pizza string

函数 (p pie) String() string{
返回 "pie"
}

函数 (p pizza) String() string{
返回 "pizza"
}

函数 main(){
变量 a pie
变量 b pizza
fmt.Println(a,b) //fmt.Println() 会寻找 Stringer 并调用它们的 String() 方法。
}

英文:
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

得分: 1

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

package main

import (
    "encoding/json"
    . "fmt"
)

func main() {
    var i interface{} = c

    e := func() error { return c } // 类型错误接口{ Error() string}
    Println(e())                   // 嘶嘶声

    s := func() Stringer { return d } // 类型Stringer接口{String() string}

    // func Println(a ...interface{}) (n int, err error)
    Println(s()) // 汪汪声

    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#errors和https://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。如果参数是Stringer,fmt.Println将调用String方法。请参阅https://talks.golang.org/2013/go4python.slide#33。func() 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/go4gophers和https://talks.golang.org/2014/go4gophers.slide#1。

英文:

Extending @Jessta excellent example. A simple example of the use of Go's' interface in a working program to access Go's standard library is given.

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" }

Interfaces are Go's most distinctive and powerful feature. They have a profound effect on library design. They enable true component architectures. Prime examples are io.Reader and io.Writer, generalizations of the Unix pipe idea. See https://talks.golang.org/2015/simplicity-is-complicated.slide.

By convention, errors have type error, a simple built-in interface. See https://golang.org/doc/effective_go.html#errors and https://talks.golang.org/2012/splash.article. An error variable represents any value that can describe itself as a string. func() error { return c } calls type error interface { Error() string}. func (cat) Error() string implements type error interface { Error() string}. See https://blog.golang.org/error-handling-and-go.

A Stringer can pretty print itself. Anything that implements String is a Stringer. fmt.Println calls the String method if the parameter is a Stringer. See https://talks.golang.org/2013/go4python.slide#33. func() Stringer { return d } calls type Stringer interface {String() string}. func (dog) String() string implements type Stringer interface {String() string}.

The signature of fmt.Println is func Println(format string, a ...interface{}) (n int, err error) which is to say its arguments (after the format string) are interface values. See https://blog.golang.org/constants. Quotes edited to match example.

Pervasive use of key interfaces in the standard library make it easy to chain APIs together. See https://talks.golang.org/2012/goforc.slide#46. See https://talks.golang.org/2014/go4gophers and https://talks.golang.org/2014/go4gophers.slide#1 for more examples.

答案5

得分: 0

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

最好的例子是Writer接口。Rob Pike在他在Google Tech Talk的介绍演讲中有一个例子(http://www.youtube.com/watch?v=rKnDgT73v8s)- 在演讲的33:25处可以找到他的解释。

英文:

The base concept of interfaces in Go, is that any object implementing a method defined an interface, can be a part of that interface.

The best example is the Writer interface. Rob Pike has an example of this in his intro speech at Google Tech Talk ( http://www.youtube.com/watch?v=rKnDgT73v8s ) - scroll to 33:25 into the speech for his explanation.

答案6

得分: 0

维基百科解释了鸭子类型,并且有一个Go语言的例子。
http://en.wikipedia.org/wiki/Duck_typing

英文:

Wikipedia explains duck-typing and has an example in Go.
http://en.wikipedia.org/wiki/Duck_typing

huangapple
  • 本文由 发表于 2009年11月15日 00:07:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/1734673.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定