go和python中的鸭子类型--Duck Typing

鸭子类型(duck typing):是动态类型的一种风格,不管对象属于哪个,也不管声明的具体接口是什么,只要对象实现了相应的方法,函数就可以在对象上执行操作.
即忽略对象的真正类型,转而关注对象有没有实现所需的方法、签名和语义.

在这里插入图片描述
图片中的大黄鸭,它是不是一只鸭子呢?

这个问题,得看你从哪个角度去看,如果从人们常识的认知中的角度去看,它显然不是一只鸭子,因为它连最基本的生命都没有。

但是从 Duck Typing 的角度来看,它就是一只鸭子!

鸭子类型这一名字出自James Whitcomb Riley在鸭子测试中提出的如下的表述:

当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被
称为鸭子。

Python 中的 Duck Typing

先看一个函数:

def down(fetcher):
	return fetcher.get("http://xxx");

有一个 down 函数,传过来一个 fetcher 参数,fetcher 是可以获取一个 url 链接的资源的。
这个 fetcher 就是一个 Duck Typing 的对象,使用者约定好这个 fetcher 会有一个 get 函数就可以了。

显然这个 down 函数会有以下问题:

运行时才知道传入的 fetcher 有没有 get 函数。那么站在 download 函数的使用者的角度上看,我怎么知道需要给 fetcher 实现 get 方法呢?实际情况中,可能 down 函数的代码很长,可能 fetcher 不只要实现 get 方法,还有其它方法需要实现。通常这种情况需要通过加注释来说明。

Go 中的 Duck Typing

如果 fetcher 参数需要同时实现两个或以上的接口方法时,实现如下

type Fetcher interface {
   	Get(url string) string
}

type Saver interface {
   	Save(content string)
}

type FetcherAndSaver interface {
    Fetcher
    Saver
}

func down(f Fetcher) string {  // Fetcher 接口的down方法
    return f.Get("http://xxx")
}

func save(f Saver) {   // Saver 接口的save方法
    f.Save("some thing")
}

func downAndSave(f FetcherAndSaver) {
    content := f.Get("http://xxxx")
    f.Save(content)
}

// 实现者
type MyFetcherAndSaver struct {

}

func (f MyFetcherAndSaver) Get(url string) string {
    ...
}

func (f MyFetcherAndSaver) Save(content string) {
    ...
}

func main() {
    f := MyFetcherAndSaver{}
    down(f)
    save(f)
    downAndSave(f)
}

这里定义了三个接口,只要有 Get 方法的就是 Fetcher,只要有 Save 方法的就是 Saver,同时有 Get 方法和 Save 方法就是 FetcherAndSaver 。

实现者 MyFetcherAndSaver 并不需要声明它实现了哪些接口,只要它有相关接口的所定义的方法,那么它的实例,就即能作为 Fetcher 接口来使用,又能作为 Saver 接口来使用,也能作为 FetcherAndSaver 接口来使用。

Go 的实现方法相对比较灵活,又不失类型检查。总的来说,特点有:

(1) 能同时实现多个接口
(2) 和python相比 , go 中的 Duck Typing 更加灵活
(3) fetcher 有没有 get 方法,python 是运行时才知道,go 是编译时就知道

发布了41 篇原创文章 · 获赞 8 · 访问量 1947

猜你喜欢

转载自blog.csdn.net/big_white_py/article/details/103901580
今日推荐