Go基础之面向接口

在这里插入图片描述

1. Duck Typing

“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。” 我们并不关心对象是什么类型,到底是不是鸭子,只关心行为。
在面向对象的编程语言中,当某个地方(比如某个函数的参数)需要符合某个条件的变量(比如要求这个变量实现了某种方法)时,如果判断这个变量是否“符合条件”的标准是: 这个变量的类型是否实现了这个要求的方法(并不要求显式地声明),那么这种语言的类型系统就可以称为 duck typing。

Python 中的duck typing

def greeting(a):
     return a.sayHello()
 
 class Duck(object):
     def sayHello(self):
        print('ga ga ga!')
 
 class Person(object):
     def sayHello(self):
         print('Hello!')
 
duck = Duck()
person = Person()
greeting(duck)
greeting(person)

上面这段 Python 代码中, greeting 函数对参数 a 只有一个要求: a 必须实现 sayHello 这个方法。因为 Duck 类和 Person 类都实现了 sayHello,那么这两个类型的实例,duck 和 person,都可以用作 greeting 的参数。这就是python中duck typing的体现。

Go duck typing
使用过 Python 的人都知道写代码写起来很快。但是缺陷也是显而易见的:错误往往要在运行时才能被发现。比如上面的 greeting 函数,你可以传递任何一个变量作为参数,但是要是这个变量没有 sayHello 这个方法或者属性,那么程序运行时就会出错。相反,静态类型语言往往在编译时就是发现这类错误:如果某个变量的类型没有显式声明实现了某个方法/接口,那么,这个变量就不能用在要求一个实现了这个接口的地方。

Go 的类型系统采取了折中的办法:1)一个类型不需要显式地声明它实现了某个接口;2)但仅当某个变量的类型实现了某个接口的方法,这个变量才能用在要求这个接口的地方。

package main

import (
    "fmt"
)

type Say interface {
    Hello()
}

type Person struct {}

func (person *Person) Hello() {
    fmt.Printf("Hello!")
}
type Duck struct {}

func (duck *Duck) Hello() {
    fmt.Printf("ga ga ga!")
}

func greeting(s Say) {
    s.Hello()
}

func main () {
    p := Person{}
    d   := Duck{}
    greeting(p)
    greeting(d)
}
2.Go 语言接口

Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。
接口定义

type Namer interface {
    Method1(param_list) return_type  //方法名(参数列表) 返回值列表
    Method2(param_list) return_type  //方法名(参数列表) 返回值列表
}

接口实现
隐式实现:实现接口的类并不需要显式声明,只需要实现接口所有的函数就表示实现了该接口,而且类还可以拥有自己的方法。

package main
  
import "fmt"
  
type Shaper interface {
    Area() float64
}
  
type Rectangle struct {
    length float64
    width  float64
}
  
// 实现 Shaper 接口中的方法
func (r *Rectangle) Area() float64 {
    return r.length * r.width
}
  
// Set 是属于 Rectangle 自己的方法
func (r *Rectangle) Set(l float64, w float64) {
    r.length = l
    r.width = w
}
  
func main() {
    rt := new(Rectangle) //创建指针类型的结构体实例(类实例)
    rt.Set(2, 3)
    s := Shaper(rect) //这里将指针类型实例赋值给接口
    s = rt //也可以
    fmt.Printf("area: %f\n", s.Area())
}

接口赋值

只要两个接口拥有相同的方法列表(与次序无关),即是两个相同的接口,可以相互赋值;
接口赋值只需要接口A的方法列表是接口B的子集(即假设接口A中定义的所有方法,都在接口B中有定义),那么B接口的实例可以赋值给A的对象。

接口嵌套
接口可以嵌套,嵌套的内部接口将属于外部接口,内部接口的方法也将属于外部接口。另外在类型嵌套时,如果内部类型实现了接口,那么外部类型也会自动实现接口,因为内部属性是属于外部属性的。

type ReadWrite interface {
    Read(b Buffer) bool
    Write(b Buffer) bool
}
  
type Lock interface {
    Lock()
    Unlock()
}
  
type File interface {
    ReadWrite
    Lock
    Close()
}

接口断言/类型转换

if v, ok : = varI.(T) ; ok { // checked type assertion<//do something
    return
}
// 如果 v 是 varI 转换到类型 T 的值,ok 会是 true;否则 v 是类型 T 的零值,ok 是 false。 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值