[翻译]Interfaces in Go

原创
2013/02/04 14:31
阅读数 72

Interfaces are contracts that exist between an expected implementation of a functionality and its actual implementation. In real life there are innumerable interfaces that we are implicitly bound to and that we expect of others. When we put money in a bank, we expect that the money is there the next day and if they have promised us a daily interest, then that we have the additional amount. How the bank keeps the money safe and how it generates the amount for the interest is not something we usually concern ourselves with. This implicit contract is our interface with the bank, and also therefore, the bank’s interface with us. 

接口在功能定义和功能实现之间定立了约定 在现实生活中 有很多接口的例子 我们去银行存钱 我们期望我们今天存进去的钱 明天还是在我们的名底下 如果在存钱的时候银行承诺了利息 我们可以看到随着时间 我们的存款在增加 即使没有通货膨胀来的厉害 银行如何保管这些钱 以及它是如何产生利息的 我们通常不会关心 除非你想劫个道 或者做个会计师 呵呵 这个场景中 银行和我们有一个约定 我们通过这个约定和银行发生一些正当的关系

In programming, interfaces follow a similar model. We will work out an example that uses Go’s idea of interfaces, which is different from interfaces in programming languages like Java, C++, C#, etc. which have object oriented constructs. Go being procedural implements it differently, but it works just as well and has many positive downstream implications. 

在编程领域 接口遵循类似的模型 我们会写一个Go的接口 它和其它的面向对象的语言 像Java C++ C#等不太一样 Go作为非面向对象性语言 在实现接口的时候会有所区别 但是 Go的接口可以达到我们的要求 并且提供了其它语言不及的好处

Our example takes us through getting the area of various shapes. A rectangle is a shape, a square is a shape, a circle is a shape … and a shape has an area. So Shape, which is an abstract concept, can be an interface. And actual shapes like a circle, rectangle, triangle, etc. can provide its own area. And we can then have a unified way of getting the area of different shapes. 

我们的例子是计算各种形状的面积 矩形是多边形 正方形 圆 都是多边形 它们都可以计算面积 多边形是抽象的概念 可以是一个接口 但是具体的形状 比如圆 矩形等 是可以实实在在地得到它们的面积 我们可以通过统一的方法来得到不同形状的面积

If you are new to programming, the impact of such an idea might not be clear right now, but it is very powerful. If you have traveled to places where you did not know the language, you might have struggled to get information as and when you needed it. "When will the train arrive?" - what if there was one consistent asking that irrespective of where you were in the world. Well, there isn’t, which is why we have to go through the shortened sentences, higher voices, hand waving, pointing at things, writing it out and so on and so forth. In computing too, we have to deal with various types of objects and in order that we may interact with them consistently, interfaces are used. 

假设你刚接触编程 这个抽象的接口概念对你来说 也许不是很清晰 但是 可以明确地告诉你 这个概念很给力 假设你一气之下离家出走 去了一个语言不通的地方 对你来说 想要吃饱饭也许都是问题 要么不会点菜 要么无法和服务员交流 清楚地表达你的意思 可能出现的情况就是 各种各样的人 都会用他们的不同的方式来问同样的问题 这个时候也许就需要有一个神奇的机器 类似ATM一样 不管你选择什么样的语言 英语或者中文 你只要按着它的提示点击屏幕 你就是存取现金 这样的好处在于 你不需要英语用一台ATM 中文又是在另一台ATM机上操作了吧 在软件领域 在编程过程中 我们需要面对各种不同类型的对象 我们希望可以在和它们交互的时候提供统一的接口

In the first step, we shall go through just creating a simple rectangle class and print its area.

废话有点多了 现在就写一个简单的矩形 并且计算它的面积 

package main



import "fmt"



//define a Rectangle struct that has a length and a width 定义矩形 长和宽

type Rectangle struct { 

   length, width int

}



//write a function Area that can apply to a Rectangle type 定义计算面积的方法

func (r Rectangle) Area() int {

   return r.length * r.width

}



func main() {

   r := Rectangle{length:5, width:3} //define a new Rectangle instance with values for its properties

   fmt.Println("Rectangle details are: ",r)  

   fmt.Println("Rectangle's area is: ", r.Area())

}



Rectangle details are: {5 3}

Rectangle's area is: 15

At this point, this code has no interfaces. As we proposed earlier, let us now add interfaces. The Area function is what we will abstract out into the interface called Shaper. 

目前为止 还没有涉及到接口 现在我们添加接口的相关代码 计算面积的函数 就是我们要抽象出来作为接口Shaper的受害者

In Go, the convention is to "er" a type to indicate that it is an interface. Shape is best named Shaper when it is an interface. Convert is best named Converter when it is an interface. Not doing so won’t crash your program but it is useful to follow convention as it will be easier for others reading the code to understand what is intended.

Go有个接口类型名字的惯例 就是名字后加er 这里就是Shaper 不这样定义也ok 但是便于同行理解 还是按规矩办事吧

package main



import "fmt"



//Shaper is an interface and has a single function Area that returns an int.

type Shaper interface {

   Area() int

}



type Rectangle struct {

   length, width int

}



//this function Area works on the type Rectangle and has the same function signature defined in the interface Shaper.  Therefore, Rectangle now implements the interface Shaper. 这个函数可以通过Recangle类型来调用 它的申明和Shaper接口一致 实现了Shaper接口

func (r Rectangle) Area() int {

   return r.length * r.width

}



func main() {

   r := Rectangle{length:5, width:3}

   fmt.Println("Rectangle r details are: ", r)  

   fmt.Println("Rectangle r's area is: ", r.Area())  



   s := Shaper(r)

   fmt.Println("Area of the Shape r is: ", s.Area())  

   

}



Rectangle r details are: {5 3}

Rectangle r's area is: 15

Area of the Shape r is: 15

In languages like Java and C#, a type or class that intends to provide implementation for an interface needs to explicitly state that. So in Java, one would have to do:

Java C# 需要显式地声明哪个类实现了哪个接口 如下:

public class Rectangle implements Shaper { //implementation here }

In Go however, such explicit declaration of implementation is not required. And you can see that in the code. The Shaper interface is defined with a single method Area() int. The Rectangle type has a function with the same signature: func (r Rectangle) Area() int. So Go automatically understands that the Rectangle type implements the Shaper interface. Therefore you can cast a Rectangle type to be a Shaper type s := Shaper(r) and call the Area function on it: s.Area().

但是Go并不需要用关键字(implement)显式地声明 这一点你也许已经在代码里看出来了 Shaper接口只定义了一个函数Area() int Rectangle类型实现这个接口 Go很聪明地理解你的代码的意图 知道Rectangle实现了这个接口 所以你可以把Rectangle类下那个转换成Shaper接口 s := Shaper(r) 并且调用Area函数 s.Area()

So far we have achieved only the same result as before. Let’s add a Square type now and see how interfaces can be used to make the Area call uniformly. 

至此 我们可以得到和没有使用接口时的结果 现在 我们再添加一个Square类型 看看Go是如何统一地使用接口来计算不同形状的面积

package main



import "fmt"



type Shaper interface {

   Area() int

}



type Rectangle struct {

   length, width int

}



func (r Rectangle) Area() int {

   return r.length * r.width

}



type Square struct {

   side int

}



//the Square type also has an Area function and therefore, it too, implements the Shaper interface 正方形的面积就是边长的平方嘛

func (sq Square) Area() int {

   return sq.side * sq.side

}



func main() {

   r := Rectangle{length:5, width:3}

   fmt.Println("Rectangle details are: ",r)  



   var s Shaper

   s = r //equivalent to "s = Shaper(r)" since Go identifies r matches the Shaper interface

   fmt.Println("Area of Shaper(Rectangle): ", s.Area())

   fmt.Println()



   q := Square{side:5}

   fmt.Println("Square details are: ",q)  

   s = q //equivalent to "s = Shaper(q)

   fmt.Println("Area of Shaper(Square): ", s.Area())

   fmt.Println()

}



Rectangle details are: {5 3}

Area of Shaper(Rectangle): 15



Square details are: {5}

Area of Shaper(Square): 25

We now have a Square type also, and in a fashion similar to that of Rectangle, we are able to obtain its area. Let’s get similar output again, but using a loop which will give an indication how interfaces can produce cleaner, simpler, and more scalable code. In the below code we create an array of Shaper instances and then loop through them calling the Area function on each. Same effect as before, but now with improved possibilities. 

ok Square类型已经完成了 和Rectangle类型类似 通过同样的方法计算面积 下面这段代码创建了一个Shaper数组 遍历这个数组 对每一个元素调用Area函数 结果和之前一样 

package main



import "fmt"



type Shaper interface {

   Area() int

}



type Rectangle struct {

   length, width int

}



func (r Rectangle) Area() int {

   return r.length * r.width

}



type Square struct {

   side int

}



func (sq Square) Area() int {

   return sq.side * sq.side

}



func main() {

   r := Rectangle{length:5, width:3}

   q := Square{side:5}

   shapesArr := [...]Shaper{r, q}



   fmt.Println("Looping through shapes for area ...")

   for n, _ := range shapesArr {

       fmt.Println("Shape details: ", shapesArr[n])

       fmt.Println("Area of this shape is: ", shapesArr[n].Area())

   }

}

Looping through shapes for area ...

Shape details: {5 3}

Area of this shape is: 15

Shape details: {5}

Area of this shape is: 25

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部
返回顶部
顶部