6.1 Go语言中接口使用样例

码界捕手漫游
• 阅读 624

正如前文提到,Go语言并没有类的定义,接口可以说Go语言最接近于类的实现方式,但是更轻量。对于接口的学习,如果从原理层面理解学习起来比较慢,所以建议先从代码使用维度进行理解,最终回归到原理层面加深理解。

需求与分析

假设我们有一组图形,需要计算每个图形的面积,并计算他们的面积之和。那么最简单的方法就是分别计算他们的面积,并进行相加,我们来尝试实现一下。

不使用接口的实现

在这个代码实现中,我们需要将两种不同形状,矩形(rect)和圆形(circle)的面积求和,因此我们定义了如下内容:

  • 两个结构体,矩形是长和宽,圆形是半径
  • 分别实现了两个求面积的方法area(),矩形的面积等于长乘以宽,而圆形面积则是半径的平方乘以Pi
  • 在求和部分,我们直接定义了一个float64的数组,将面积直接存入该数组中
  • 通过循环进行求和

虽然上述方式能够满足我们的需求,但是如果我们需要增加一个计算周长的方法时,我们的代码会变得非常冗余并且可读性变差,因此我们用接口尝试来改造我们的代码。

package main

import (
    "fmt"
    "math"
)

type rect struct {
    width float64
    height float64
}

func (r rect) area() float64 {
    return r.width * r.height
}

type circle struct {
    radius float64
}

func (c circle) area() float64 {
    return math.Pi * c.radius * c.radius
}

func main() {
    var areaSum float64
    
    // Intial circle and rect struct type
    c1 := circle{2.5}
    r1 := rect{3, 4}
    
    // Save all area results into an array
    shapeAreas := []float64{c1.area(), r1.area()}
    
    // Sum all area together
    areaSum = 0
    for _, area := range shapeAreas {
        areaSum += area
    }
    
    fmt.Printf("Sum area = %v\n", areaSum)
}

使用接口的实现

相较于上述代码,我们做了如下优化:

  • 定义了一个新的interface shape,包含一个area()方法,即实现了area()的struct,就实现了shape接口
  • 在结构体定义,area()计算部分我们并没有修改
  • 在主函数中,我们重新定义了一个类型为shape interface的数组,该数组中无须再计算area(),只需要将两个不通类型存放在该数组中
  • 在循环过程中,我们直接调用每个shape interface中的area()方法,即可完成面积求和
package main

import (
    "fmt"
    "math"
)

// Define a new interface, contain a method define and type is float64
type shape interface {
    area() float64
}

type rect struct {
    width float64
    height float64
}

func (r rect) area() float64 {
    return r.width * r.height
}

type circle struct {
    radius float64
}

func (c circle) area() float64 {
    return math.Pi * c.radius * c.radius
}

func main() {
    var areaSum float64
    
    // Intial circle and rect struct type
    c1 := circle{2.5}
    r1 := rect{3, 4}
    
    // Previous: Save all area results into an array
    // Previous: shapeAreas := []float64{c1.area(), r1.area()}
    
    // Define an array with new shape interface
    shapes := []shape{c1, r1}
    
    // Previous: Sum all area together
    areaSum = 0
    // Previous: for _, area := range shapeAreas {
    // Previous:     areaSum += area
    // Previous: }
    
    // Implement a new loop
    for _, shape := range shapes {
        areaSum += shape.area()
    }
    
    fmt.Printf("Sum area = %v\n", areaSum)
}

接口作为函数参数

进一步优化代码,我们将接口作为参数,在主函数中调用时,只需要传入相应类型就会自动根据类型调用相应的计算面积的方法。

package main

import (
    "fmt"
    "math"
)

// Define a new interface, contain a method define and type is float64
type shape interface {
    area() float64
}

type rect struct {
    width float64
    height float64
}

// NOTE: 接口类型为rect
func (r rect) area() float64 {
    return r.width * r.height
}

type circle struct {
    radius float64
}

// NOTE: 接口类型为circle
func (c circle) area() float64 {
    return math.Pi * c.radius * c.radius
}

func getArea(s shape) float64 {
    return s.area()
}

func main() {
    var areaSum float64

    // Intial circle and rect struct type
    c1 := circle{2.5}
    r1 := rect{3, 4}

    // Previous: Save all area results into an array
    // Previous: shapeAreas := []float64{c1.area(), r1.area()}

    // Define an array with new shape interface
    shapes := []shape{c1, r1}

    // Previous: Sum all area together
    areaSum = 0
    // Previous: for _, area := range shapeAreas {
    // Previous:     areaSum += area
    // Previous: }

    // Implement a new loop
    for _, shape := range shapes {
        areaSum += getArea(shape)
    }

    fmt.Printf("Sum area = %v\n", areaSum)
}
本文由博客一文多发平台 OpenWrite 发布!
点赞
收藏
评论区
推荐文章
九路 九路
4年前
go语言 init 函数的妙用
从程序逻辑结构角度来看,Go包(package)是程序逻辑封装的基本单元,每个包都可以理解为一个”自治“的、封装良好的、对外部暴露有限接口的基本单元。一个Go程序就是由一组包组成的。在Go包这一基本单元中分布着常量、包级变量、函数、类型和类型方法、接口等,我们要保证包内部的这些元素在被使用之前处于合理有效的初始状态,尤其是包级变量。在Go语言中
科工人 科工人
4年前
一文吃透 Go 语言解密之接口 interface
转载:大家好,我是煎鱼。自古流传着一个传言...在Go语言面试的时候必有人会问接口(interface)的实现原理。这又是为什么?为何对接口如此执着?实际上,Go语言的接口设计在整体扮演着非常重要的角色,没有他,很多程序估计都跑的不愉快了。在Go语言的语义上,只要某个类型实现了所定义的一组方法集,则就认为其就是同一种类型,是一个东西。大家常常称其
go语言中,数组与切片的区别?
切片是Go语言核心的数据结构,然而刚接触Go的程序员经常在切片的工作方式和行为表现上被绊倒。比如,明明说切片是引用类型但在函数内对其做的更改有时候却保留不下来,有时候却可以。究其原因是因为我们很多人用其他语言的思维来尝试猜测Go语言中切片的行为,切片这个内置类型在Go语言底层有其单独的类型定义,而不是我们通常理解的其他语言中数组的概念。文章
Nick16 Nick16
4年前
Go语言开发的利与弊
Go语言有多火爆?国外如Google、AWS、Cloudflare、CoreOS等,国内如七牛、阿里等都已经开始大规模使用Go语言开发其云计算相关产品。在Go语言的使用过程中,需要注意哪些Yes和But?最近,我们使用Go语言编写了一个API,Go语言是一种开源编程语言,2009年由Google推出。在使用Go进行开
Stella981 Stella981
3年前
Go 用 interface 模拟多态
多态是C这种语言中的概念,是指对不同的子类对象运行自己定义的方法。在Go语言中没有类的概念,但仍然可以使用structinterface来模拟实现类的功能。下面这个例子演示如何使用Go来模拟C中的多态行为。packagemainimport"fmt"//首先定义了一
Wesley13 Wesley13
3年前
go 学习笔记之10 分钟简要理解 go 语言闭包技术
闭包是主流编程语言中的一种通用技术,常常和函数式编程进行强强联合,本文主要是介绍Go语言中什么是闭包以及怎么理解闭包.如果读者对于Go语言的闭包还不是特别清楚的话,可以参考上一篇文章go学习笔记之仅仅需要一个示例就能讲清楚什么闭包(https://www.oschina.net/ac
Wesley13 Wesley13
3年前
go 的匿名函数和闭包
匿名函数匿名函数是指不需要定义函数名的一种函数实现方式。在Go语言中,函数可以像普通变量一样被传递或使用,这与C语言的回调函数比较类似。不同的是,Go语言支持随时在代码里定义匿名函数。匿名函数由一个不带函数名的函数声明和函数体组成,如下所示:!(https://
Wesley13 Wesley13
3年前
Go接口
Go接口的定义Go语言不是一种 _“传统”_ 的面向对象编程语言:它里面没有类和继承的概念。但是Go语言里有非常灵活的 接口(Interfacesarenamedcollectionsofmethodsignatures) 概念,通过它可以实现很多面向对象的特性。接口提供了一种方式来 说明 对象的