写点什么

Go 中如何使用 Interfaces

用户头像
baiyutang
关注
发布于: 刚刚
Go 中如何使用 Interfaces

译者:baiyutang

原文:https://www.digitalocean.com/community/tutorials/how-to-use-interfaces-in-go

介绍

编写灵活、可复用和模块化的代码对开发通用性程序是至关重要的。以这种方式工作的代码易于维护、避免需要在多处修改相同的代码。做到这一点,因语言而异。对于接口,继承是一个被使用的共同的方式,像 Java、C++、C#等等。


通过组合,开发者也能实现相同的目标。组合是联合对象或类型到更复杂之中的方式。这是 Go 用来提高代码可复用、模块化和灵活性的方式。Go 的接口提供了组织复杂组成的方式,学习如何使用接口将允许你创建通用性、可复用的代码。


这篇文章中,我们将学习如何组合具有常见行为的自定义类型,将允许我们复用代码。我们也能学习如何实现我们自定义类型的接口,以满足从另外一个包中定义接口。

定义行为

组合的核心实现之一就是接口的使用。一个接口定义了一种类型的一个行为。Go 标准库中最普遍使用的接口是 fmt.Stringer 接口:

type Stringer interface {    String() string}
复制代码


第一行代码定义了名为 Stringer 的类型。然后它声明是一个接口。就想定义结构体,Go 使用花括号({})包裹接口的定义。相较于定义结构体,我们只需要定义接口的行为,就是“这个类型能做什么”。


Stringer 的接口例子中,唯一的行为是 String() 方法,该方法不接受参数并返回一个字符。


然后,让我们看看具有 fmt.Stringer 行为的代码:

package main
import "fmt"
type Article struct { Title string Author string}
func (a Article) String() string { return fmt.Sprintf("The %q article was written by %s.", a.Title, a.Author)}
func main() { a := Article{ Title: "Understanding Interfaces in Go", Author: "Sammy Shark", } fmt.Println(a.String())}
复制代码


我们要做的第一件事是创建一个名为 Article 的新类型,这个类型具有 TitleAuthor 字段并且他们都是 字符类型。

...type Article struct {    Title string    Author string}...
复制代码


然后,在我们的 main 函数,我们创建一个 Article 的接口类型并赋值给一个名为 a 的变量。我们给 Title 字段提供值为 "Understanding Interfaces in Go",给 Author 提供值为 "Sammy Shark"

...a := Article{    Title: "Understanding Interfaces in Go",    Author: "Sammy Shark",}...
复制代码


然后,我们通过调用 fmt.Println 打印 String 方法的结果。并且把 a.String 方法调用的结果传过去。

...fmt.Println(a.String())
复制代码


在运行程序之后,我们将看到下面的输出:

The "Understanding Interfaces in Go" article was written by Sammy Shark.
复制代码


到目前为止,我们没有使用接口,但是我们刚创建具有一个行为的类型。行为匹配到 fmt.Stringer 接口。然后,让我们看看我们如何使用该行为让我们的代码更可复用。

定义接口


package main
import "fmt"
type Article struct { Title string Author string}
func (a Article) String() string { return fmt.Sprintf("The %q article was written by %s.", a.Title, a.Author)}
func main() { a := Article{ Title: "Understanding Interfaces in Go", Author: "Sammy Shark", } Print(a)}
func Print(a Article) { fmt.Println(a.String())}
复制代码


接口中的多个行为


package main
import ( "fmt" "math")
type Circle struct { Radius float64}
func (c Circle) Area() float64 { return math.Pi * math.Pow(c.Radius, 2)}
type Square struct { Width float64 Height float64}
func (s Square) Area() float64 { return s.Width * s.Height}
type Sizer interface { Area() float64}
func main() { c := Circle{Radius: 10} s := Square{Height: 10, Width: 5}
l := Less(c, s) fmt.Printf("%+v is the smallest\n", l)}
func Less(s1, s2 Sizer) Sizer { if s1.Area() < s2.Area() { return s1 } return s2}
复制代码


package main
import ( "fmt" "math")
type Circle struct { Radius float64}
func (c Circle) Area() float64 { return math.Pi * math.Pow(c.Radius, 2)}
func (c Circle) String() string { return fmt.Sprintf("Circle {Radius: %.2f}", c.Radius)}
type Square struct { Width float64 Height float64}
func (s Square) Area() float64 { return s.Width * s.Height}
func (s Square) String() string { return fmt.Sprintf("Square {Width: %.2f, Height: %.2f}", s.Width, s.Height)}
type Sizer interface { Area() float64}
type Shaper interface { Sizer fmt.Stringer}
func main() { c := Circle{Radius: 10} PrintArea(c)
s := Square{Height: 10, Width: 5} PrintArea(s)
l := Less(c, s) fmt.Printf("%v is the smallest\n", l)
}
func Less(s1, s2 Sizer) Sizer { if s1.Area() < s2.Area() { return s1 } return s2}
func PrintArea(s Shaper) { fmt.Printf("area of %s is %.2f\n", s.String(), s.Area())}
复制代码

总结

我们已经看到如何创建更小的接口,并将其构建为更大的接口,从而只共享我们需要的功能或方法。我们也学到了我们可以从其他接口组合我们接口,包括这些从其他包定义的接口,不仅仅是我们的。

发布于: 刚刚阅读数: 2
用户头像

baiyutang

关注

广州 2017.12.13 加入

Microservices | Golang | Cloud Nitive | “Smart work,Not hard”

评论

发布
暂无评论
Go 中如何使用 Interfaces