关于go:实证与虚无抽象和具象Go-lang118入门精炼教程由白丁入鸿儒Go-lang接口interface的使用EP08

32次阅读

共计 4542 个字符,预计需要花费 12 分钟才能阅读完成。

看到接口这两个字,咱们肯定会联想到面向接口编程。说白了就是接口指定执行对象的具体行为,也就是接口示意让执行对象具体应该做什么,所以,普遍意义上讲,接口是形象的,而理论执行行为,则是具象的。

接口 (interface) 的定义

在 Go lang 中,接口是一组办法签名,当类型为接口中的所有办法提供定义时,它被称为实现接口。和面向接口的思维十分相似,接口指定了类型应该具备的办法,类型决定了到底该怎么实现这些办法:

/* 定义接口 */  
type interface_name interface {method_name1 [return_type]  
   method_name2 [return_type]  
   method_name3 [return_type]  
   ...  
   method_namen [return_type]  
}  
  
/* 定义构造体 */  
type struct_name struct {/* variables */}  
  
/* 实现接口办法 */  
func (struct_name_variable struct_name) method_name1() [return_type] {/* 办法实现 */}  
...  
func (struct_name_variable struct_name) method_namen() [return_type] {/* 办法实现 */}

具体实现形式:

package main  
  
import ("fmt")  
  
type Phone interface {call()  
}  
  
type Android struct { }  
  
func (android Android) call() {fmt.Println("I am Android")  
}  
  
type Ios struct { }  
  
func (ios Ios) call() {fmt.Println("I am Ios")  
}  
  
func main() {  
    var phone Phone  
  
    phone = new(Android)  
    phone.call()  
  
    phone = new(Ios)  
    phone.call()}

程序返回:

I am Android  
I am Ios

是的,当初咱们能够构造体、函数、以及接口三箭齐发了,这里首先定义好手机接口,并且指定 call()办法,意思是我在形象层面领有一个手机,手机应该具备打电话的性能。

随后别离定义构造体和函数(也是办法),别离具现化的实现接口的指定行为,精力上大家是一样的,但肉体上,一个是安卓,另一个则是苹果。

Go lang 中,接口能够被任意的对象实现,同样地,一个对象也能够实现任意多个接口,任意的类型都实现了空接口(interface{}),也就是蕴含 0 个 method 的 interface。

诚然,如果独自应用构造体,咱们也能够,实现相似多态的构造:



package main  
  
import "fmt"  
  
type Human struct {  
    name  string  
    age   int  
    phone string  
}  
type Student struct {  
    Human  // 匿名字段  
    school string  
    loan   float32  
}  
type Employee struct {  
    Human   // 匿名字段  
    company string  
    money   float32  
} //Human 实现 Sayhi 办法  
func (h Human) SayHi() {fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)  
} //Human 实现 Sing 办法  
func (h Human) Sing(lyrics string) {fmt.Println("。。。。。。。。", lyrics)  
} //Employee 重写 Human 的 SayHi 办法  
func (e Employee) SayHi() {  
    fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,  
        e.company, e.phone) //Yes you can split into 2 lines here.  
}

能够独自为构造体定义方法,但如果接口参加逻辑:

type Men interface {SayHi()  
    Sing(lyrics string)  
}  
  

func main() {mike := Student{Human{"Mike", 10, "1"}, "MIT", 0.00}  
    paul := Student{Human{"Paul", 20, "2"}, "Harvard", 100}  
    sam := Employee{Human{"Sam", 30, "3"}, "Golang Inc.", 1000}  
    Tom := Employee{Human{"Tom", 40, "4"}, "Things Ltd.", 5000}  
    // 定义 Men 类型的变量 i  
    var i Men  
    // i 能存储 Student  
    i = mike  
    fmt.Println("This is Mike, a Student:")  
    i.SayHi()  
    i.Sing("song")  
    // i 也能存储 Employee  
    i = Tom  
    fmt.Println("This is Tom, an Employee:")  
    i.SayHi()  
    i.Sing("song")  
    // 定义了 slice Men  
    fmt.Println("Let's use a slice of Men and see what happens")  
    x := make([]Men, 3)  
    // T 这三个都是不同类型的元素,然而他们实现了同一个接口  
    x[0], x[1], x[2] = paul, sam, mike  
    for _, value := range x {value.SayHi()  
    }  
}

程序返回:



This is Mike, a Student:  
Hi, I am Mike you can call me on 1。。。。。。。。song  
This is Tom, an Employee:  
Hi, I am Tom, I work at Things Ltd.. Call me on 4。。。。。。。。song  
Let's use a slice of Men and see what happens  
Hi, I am Paul you can call me on 2  
Hi, I am Sam, I work at Golang Inc.. Call me on 3  
Hi, I am Mike you can call me on 1

由此可见,接口的呈现,把原本不相干的构造体类型以形象的模式联合了起来,不同的类型实现内容不同的共性办法。

也就是说,Men 接口类型的变量 i,那么 i 外面能够存 Human、Student 或者 Employee 值,所以 i 是形象的,而 Human、Student 或者 Employee 就是 i 的具象化操作。

接口指定函数参数

接口不仅仅能够指定无参办法,也能够指定具体的参数,让函数承受各种类型的参数:

package main  
  
import "fmt"  
  
type Human interface {Len()  
}  
type Student interface {Human}  
  
type Test struct { }  
  
func (h *Test) Len() {fmt.Println("10 个")  
}  
func main() {  
    var s Student  
    s = new(Test)  
    s.Len()}

程序返回:

10 个

这里应用接口嵌套的模式,Human 接口定义了 Len 办法,构造体 Test 实现了所有的 Len 接口办法,当构造体 s 中调用 Test 构造体的时候,s 就相当于 Python 中的继承,s 继承了 Test,因而,s 能够不必重写所有的 Human 接口中的办法,因为父结构器曾经实现了接口。

鸭子类型(ducktyping)

什么是鸭子类型?当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就能够被称为鸭子。

所谓远看山有色,近听水无声,春去花还在,人来鸟不惊,意象上来讲,一个事物到底是不是某一种类型,取决于它具不具备这个类型的个性,这就是鸭子类型的实质。

所以鸭子类型次要形容事物的内部行为而非外部结构,在面向对象的编程语言中,比方 Python 中,一个对象无效的语义,不是由继承自特定的类或实现特定的接口,而是由 ” 以后办法和属性的汇合 ” 决定。

编写 test.py 文件:

class PsyDuck():  
    def gaga(self):  
        print("这是可达鸭")  
  
  
# 应用的对象和办法  
class DoningdDuck():  
    def gaga(self):  
        print("这是唐老鸭")  
  
  
# 被调用的函数  
def duckSay(func):  
    return func.gaga()  
  
  
# 限度调用形式  
if __name__ != '__main__':  
    print("must __main__")  
  
if __name__ == "__main__":  
  
    # 实例化对象  
    duck = PsyDuck()  
    person = DoningdDuck()  
    # 调用函数  
    duckSay(duck)  
    duckSay(person)

程序返回:

这是可达鸭  
这是唐老鸭

所以到底是什么鸭子不重要,重要的是调用了谁的实例。

再来看看 go lang 的手笔:

package main  
  
import "fmt"  
  
// 定义一个鸭子接口  
//Go 接口是一组办法的汇合,能够了解为形象的类型。它提供了一种非侵入式的接口。任何类型,只有实现了该接口中办法集,那么就属于这个类型。type Duck interface {Gaga()  
}  
  
// 假如当初有一个可达鸭类型  
type PsyDuck struct{}  
  
// 可达鸭申明办法 - 满足鸭子会嘎嘎叫的个性  
func (pd PsyDuck) Gaga() {fmt.Println("this is PsyDuck")  
}  
  
// 假如当初有一个唐老鸭类型  
type DonaldDuck struct{}  
  
// 唐老鸭申明办法 - 满足鸭子会嘎嘎叫的个性  
func (dd DonaldDuck) Gaga() {fmt.Println("this is DoningdDuck")  
}  
  
// 要调用的函数 - 负责执行鸭子能做的事件, 留神这里的参数, 有类型限度为 Duck 接口  
func DuckSay(d Duck) {d.Gaga()  
}  
  
func main() {  
    // 提醒开始打印  
    fmt.Println("duck typing")  
  
    // 实例化对象  
    var pd PsyDuck    // 可达鸭类型  
    var dd DonaldDuck // 唐老鸭类型  
  
    // 调用办法  
    DuckSay(pd) // 因为可达鸭实现了所有鸭子的函数, 所以能够这么用  
    DuckSay(dd) // 因为唐老鸭实现了所有鸭子的函数, 所以能够这么用  
}

程序返回:

duck typing  
this is PsyDuck  
this is DoningdDuck

这里首先定义形象的鸭子接口,指定 gaga 办法,不同的构造体:可达鸭、唐老鸭别离绑定并且实现了鸭子接口的办法,而后申明一个调用函数,在执行的时候,将构造体变量传递给调用函数,动静地实现了不同类型的办法。

结语

所谓接口 (interface) 的抽象性,就是从外表看到实质,从全面看到整体,而后抽出那些稳固的、共有的个性。平时咱们会思考代码的重用性,组件的复用性,同一个性能对不同场景的复用性,有了复用的能力,就可能用更少的开发去满足更多场景的同类需要问题。从而可能从一个具体的需要,看到一类的需要,看到衍生的相干的需要,甚至再对需要进行分类,看到更高层面的需要。进而才可能系统性解决同类的需要而不是就事论事点对点解决问题。

所以,总的来说,接口的极致就是形象,而形象的极致,则是格局,接口,能够更好的帮咱们扩充程序视线的格局。

正文完
 0