我发现了一篇关于 Go 的有趣博客文章。
我正在尝试理解接口的概念,但我发现从博客文章中的代码片段很难做到这一点,而从语言规范来看几乎是不可能的。
任何人都可以在工作程序中指出一个简单的 Go 接口示例吗?
这是一个正在进行的学习练习,当然也是一个很好的风格的糟糕例子,但是你去(规范)。
此外,作为一个更奇特的例子,我在 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);
}
教程“ Go 中的接口 - 第 2 部分:帮助适应性、进化设计”(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
}
该功能已被扩展,核心类或核心层次结构没有任何更改。这种实现更加简洁,易于扩展,并且可以随着项目需求的不断变化而更好地扩展。
文章以 John Asmuth 引用的关于 Go 中接口的生产力的帖子结尾:
“事实上,我不必花时间预先设计某种类型的层次结构,然后在我完成之前重新排列它两到三遍。
这甚至不是很容易做到正确的事实 -
这是事实我只是不必担心它,可以继续使用实际的算法。 ”
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.
}
扩展@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。
按照惯例,errors 有类型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。
纵梁可以漂亮地打印自己。任何实现 String 的东西都是 Stringer。fmt.Println
如果参数是 Stringer,则调用 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。
Go 中接口的基本概念是,任何实现定义了接口的方法的对象都可以成为该接口的一部分。
最好的例子是 Writer 接口。Rob Pike 在他的 Google Tech Talk ( http://www.youtube.com/watch?v=rKnDgT73v8s )的介绍性演讲中举了一个例子——滚动到演讲的 33:25 以获取他的解释。
Wikipedia 解释了鸭式打字并在 Go 中有一个示例。 http://en.wikipedia.org/wiki/Duck_typing