长安链 DApp 开发必学 Go 09

191 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第23天,点击查看活动详情

本文已参与「开源摘星计划」,欢迎正在阅读的你加入。活动链接:github.com/weopenproje…

经过上面几章的学习,我们已经掌握了 go 语言中“方法”(Method)的使用方式。详细的介绍了“接收者”(Receiver),它分为“指针接收者”(Pointer Receiver)和“数值接收者”(Value Reciever)。

根据官方教程的建议,我们大部分的时候,都要使用“指针接收者”,不管是否需要修改结构体的属性,这也符合在其他语言中使用“类”时的逻辑。

这一章,继续介绍 go 语言中一种新的类型——“接口”(Interface)类型。

接口类型内定义了一系列方法的签名。当我们定义结构体,并实现了相应的方法时,就算实现了接口。定义都是比较抽象的,让我们来看代码:

package main

import (
	"fmt"
	"math"
)

type Abser interface {              // 定义接口 Abser
	Abs() float64               // 定义接口方法 Abs
}

func main() {
	var a Abser                 // a 为自定义的接口类型——Abser
	
        // MyFloat 和 Vertex 都在下方实现了 Abs 方法
        f := MyFloat(-math.Sqrt2)   
	v := Vertex{3, 4}

	a = f  // a MyFloat implements Abser
	a = &v // a *Vertex implements Abser
        
        注意!当使用了指针接收者时,必须获取 v 的指针,而不是 v 本身。下面的写法会报错
	// a = v

	fmt.Println(a.Abs())
}

type MyFloat float64                      // 定义 MyFloat 并实现接口的方法

func (f MyFloat) Abs() float64 {
	if f < 0 {
		return float64(-f)
	}
	return float64(f)
}

type Vertex struct {                      // 定义 Vertex 并实现接口的方法
	X, Y float64
}

func (v *Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

可以看到,go 语言中的“接口”类似于其他语言中的“抽象函数”。通过“接口”,定义一系列方法的签名,然后在具体的“方法”中实现。

根据官方的教程,go 语言中的接口实现是“隐式的”(implicitly),即咱们只要实现了接口里定义好的方法签名,go 会自动的帮我们进行映射:

package main

import "fmt"

type I interface {           // 定义接口 I,包含方法 M 的签名
	M()
}

type T struct {              // 定义结构体 T
	S string
}

func (t T) M() {             // 实现结构体 T 的 M 方法
	fmt.Println(t.S)
}

func main() {
	var i I = T{"hello"}  // 定义一个 I 类型的 i 变量
	i.M()
}

结构体 T 实现了 M 方法,即成为接口类型 I。根据官方教程的说法,这样做的好处是可以“解耦”接口的定义和实现。

作为 python 的拥趸,我个人是不赞成这样的做法。能写清楚的,尽量写清楚。而且,这样也会使得“命名空间”互相侵入,无法施展威力。

python 如果能变成 typepython,我想一定会更加流行~

ok,下一章我们继续探索 go 的接口(interface)