Go 中的接口
接口是一种存在于具体实现与预期实现之间的约定,接口定义了某一种函数或者方法应该怎么执行,需要接收什么样的参数,返回什么样儿的结果,而由各种不同的函数或者方法去做具体的实现,每一个实现同一个接口的函数则不需要做完全一样的处理。
以我们的生活来做一个比法,买东西付钱这是一个接口,但是具体去实现这个接口的人,则有可能会出现各种各样不同的实现方式,比如我刷卡支付,而你却是现金支付,还可能有一个他使用的是银行汇款,但是不管使用的是什么方式,我们都实现了买东西付钱这个接口。
在软件中,接口遵循与我们生活中的这种现像类似的模式,本文我将介绍在Go中如何有别于其它的如 C/C++、Java等面向对象的编程语言不一样的方法来实现接口。Go的接口的实现虽然与其它你所熟悉的语言有很大的不同,但是它工作得却非常的好。
我们的示例的需求是求各种各样形状的面积,比如矩形/方形/圆等等,因为形状可以做为一个接口,它只是一个抽象的概念,而实际形状,则是形状接口的不同实现,我们我们就可以获得一个统一的获取不同形状的面积的方法。如果你还没有任何编程经验,那可能到现在为止对接口的理解可能还是有一些模糊,但是你应该要知道接口是一种十分强大的编程思想——想想,在全世界都有同样的一个需求的时候,我们定义了一个统一的接串口,这样,你不管走到哪里都能以同样的方式完成,虽然有可能完成的过程不一样,但是你总是知道给了钱就可以拿到自己购买的商品,
在Go Structs 中的方法与Go 中的 Struct——无类实现面向对象编程我们已经有过对长方形面积的求取方式,我们创建了一个名为 Rectangle 的Struct,然后绑定了一个 Area函数到Rectangle 上来求取Rectangle实例的面积。但是代码却没有接口,所以,Area方法只能被 Rectangle使用,现在让我们将其扩展成为接口。
package main
import "fmt"
// Shaper是一个接口,它只有一个函数 Area返回一个int类型的结果
type Shaper interface {
Area() int
}
type Rectangle struct {
length, width int
}
// 该 Area 函数工作于 Rectangle 类型,同时与 Shper有同样的定义,现在就称为Rectangle实现了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在如 Java 或者C#这些语言中,一个类型或者类如果需要实现某个接口,需要这样的:
public class Rectangle implements Shaper { // implementation here }但是在Go中,我们并不需要像上面Java或者C#那样声明一个实现,你可以看到代码中,Shaper接口仅仅只是被定义了,它有一个方法 Area() int*,而 Rectangle 类型也有一个与 Shaper 中 Area 完全一样的方法声明,名称与返回类型以及接收的参数(这里不接收任何参数)都是一样的,所以Go自动的就明白了 Rectangle 实现了 Shaper 接口,所以,你可以将 Rectangle 丢 Shaper ,像这样的: *s := Shaper®,这样使用 *s.Area() 同样也可以得到该形状的面积了。
上面的其实与我们以前写的示例是一样的,现在来增加一个状态 Square :
package main
import "fmt"
// Shaper是一个接口,它只有一个函数 Area返回一个int类型的结果
type Shaper interface {
Area() int
}
type Rectangle struct {
length, width int
}
// 该 Area 函数工作于 Rectangle 类型,同时与 Shper有同样的定义,现在就称为Rectangle实现了Shaper接口
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}
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())
sq := Square{5}
fmt.Println("Square details is: ", sq)
fmt.Println("Area of square sq is: ", sq.Area())
sqs := Shaper(sq)
fmt.Println("Shaper sqs area is: ", sqs.Area())
}结果输出为:
Rectangle r details are: {5 3}
Rectangle r's area is: 15
Area of the Shape r is: 15
Square details is: {5}
Area of square sq is: 25
Shaper sqs area is: 25在上面的示例中,Square 与 Rectangle 都实现了 Shaper 接口,虽然 Square 只有一个字段 side,而 Rectangle 有 length 与 width 两个,但是 Shaper 却知道在使用 Square.Area() 时,具体使用哪一种计算方法,下面我们来看一个更简单的输出,因为 Square 与 Rectangle 都实现了 Shaper 接口,所以我们可以将上面程序的 main() 函数修改成为下面这样的:
func main() {
r := Rectangle{length: 5, width: 3}
q := Square{side:5}
shapes := [...]Shaper{r, q}
fmt.Println("Looping through shapes for area ...")
for n, _ := range shapes {
fmt.Printf("Shape detail: %v , and is area is: %dn", shapes[n], shapes[n].Area())
}
}它的输出为:
Shape detail: {5 3} , and is area is: 15
Shape detail: {5} , and is area is: 25
评论已关闭