Erlo

golang 接口_Golang之接口

2021-04-18 17:31:28 发布   232 浏览  
页面报错/反馈
收藏 点赞

什么是接口

面向对象世界中的接口的一般定义是“接口定义对象的行为”。它表示让指定对象应该做什么。实现这种行为的方法(实现细节)是针对对象的。

在 Go 语言中,接口是一组方法签名。当类型为接口中的所有方法提供定义时,它被称为实现接口。它与 OOP(面向对象) 非常相似。接口指定了类型应该具有的方法,类型决定了如何实现这些方法。

它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。换句话说,接口定义了一组方法,如果某个对象实现了某个接口的所有方法,则此对象就实现了该接口。

接口的定义

接口的定义语法如下:

/* 定义接口 */type interface_name interface {   method_name1 [return_type]   method_name2 [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 mainimport (    "fmt")// 电话结构体type Phone interface {    call()}// 诺基亚电话type NokiaPhone struct {}// 实现诺基亚电话的 callfunc (nokiaPhone NokiaPhone) call() {    fmt.Println("I am Nokia, I can call you!")}// 苹果电话type IPhone struct {}// 实现苹果电话的 callfunc (iPhone IPhone) call() {    fmt.Println("I am iPhone, I can call you!")}func main() {    var phone Phone    phone = new(NokiaPhone)    phone.call()    phone = new(IPhone)    phone.call()}

运行以上程序输出结果如下:

I am Nokia, I can call you!I am iPhone, I can call you!

说明项:

  • interface可以被任意的对象实现

  • 一个对象可以实现任意多个interface

  • 任意的类型都实现了空interface(我们这样定义:interface{}),也就是包含0个method的interface

接口的值

那么interface里面到底能存什么值呢?如果我们定义了一个interface的变量,那么这个变量里面可以存实现这个interface的任意类型的对象。

示例代码如下;

package mainimport "fmt"// 定义一个 Men 接口,声明两个方法type Men interface {    SayHi()    Sing(lyrics string)}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 %sn",     h.name, h.phone)} //Human 实现 Sing 方法func (h Human) Sing(lyrics string) {    fmt.Println("La la la la...", lyrics)} //Employee 重写 Human 的 SayHi 方法func (e Employee) SayHi() {    fmt.Printf("Hi, I am %s, I work at %s. Call me on %sn",     e.name, e.company, e.phone) }func main() {    mike := Student{Human{"Mike", 25, "222-222-XXX"}, "MIT", 0.00}    paul := Student{Human{"Paul", 26, "111-222-XXX"}, "Harvard", 100}    sam := Employee{Human{"Sam", 36, "444-222-XXX"}, "Golang Inc.", 1000}    Tom := Employee{Human{"Sam", 36, "444-222-XXX"}, "Things Ltd.", 5000}        //定义Men类型的变量 i    var i Men    // i能存储Student    i = mike    fmt.Println("This is Mike, a Student:")    i.SayHi()    i.Sing("November rain")        //i也能存储Employee    i = Tom    fmt.Println("This is Tom, an Employee:")    i.SayHi()    i.Sing("Born to be wild")        //定义了slice Men    fmt.Println("Let's use a slice of Men and see what happens")    x := make([]Men, 3)    //T这三个都是不同类型的元素,但是他们实现了interface同一个接口    x[0], x[1], x[2] = paul, sam, mike    for _, value := range x {        value.SayHi()    }}

Interface Men被 Human,Student和Employee实现,因为这三个类型都实现了这两个方法。由以上代码可知:定义了一个Men interface类型的变量m,那么m里面可以存Human、Student或者Employee值。

接口的类型

首先说一下什么是鸭子类型:如果某个东西长得像鸭子,像鸭子一样游泳,像鸭子一样嘎嘎叫,那它就可以被看成是一只鸭子。

Duck Typing,鸭子类型,是动态编程语言的一种对象推断策略,它更关注对象能如何被使用,而不是对象的类型本身。Go 语言作为一门静态语言,它通过通过接口的方式完美支持鸭子类型。

而在静态语言如 Java, C 中,必须要显示地声明实现了某个接口,之后,才能用在任何需要这个接口的地方。如果你在程序中调用某个数,却传入了一个根本就没有实现另一个的类型,那在编译阶段就不会通过。这也是静态语言比动态语言更安全的原因。

动态语言和静态语言的差别在此就有所体现。静态语言在编译期间就能发现类型不匹配的错误,不像动态语言,必须要运行到那一行代码才会报错。当然,静态语言要求程序员在编码阶段就要按照规定来编写程序,为每个变量规定数据类型,这在某种程度上,加大了工作量,也加长了代码量。动态语言则没有这些要求,可以让人更专注在业务上,代码也更短,写起来更快,这一点,写 python 的同学比较清楚。

Go 语言作为一门现代静态语言,是有后发优势的。它引入了动态语言的便利,同时又会进行静态语言的类型检查,写起来是非常 Happy 的。Go 采用了折中的做法:不要求类型显示地声明实现了某个接口,只要实现了相关的方法即可,编译器就能检测到。

总结一下,鸭子类型是一种动态语言的风格,在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由它"当前方法和属性的集合"决定。Go 作为一种静态语言,通过接口实现了鸭子类型,实际上是 Go 的编译器在其中作了隐匿的转换工作。

Go中的多态性是在接口的帮助下实现的。正如我们已经讨论过的,接口可以在Go中隐式地实现。如果类型为接口中声明的所有方法提供了定义,则实现一个接口。让我们看看在接口的帮助下如何实现多态。

任何定义接口所有方法的类型都被称为隐式地实现该接口。

类型接口的变量可以保存实现接口的任何值。接口的这个属性用于实现Go中的多态性。

接口的断言

前面说过,因为空接口 interface{}没有定义任何函数,因此 Go 中所有类型都实现了空接口。当一个函数的形参是interface{},那么在函数中,需要对形参进行断言,从而得到它的真实类型。

直接看示例代码:

package mainimport "fmt"type Student struct {}func main() {   var i1 interface{} = new (Student)   s := i1.(Student) //不安全,如果断言失败,会直接panic   fmt.Println(s)    var i2 interface{} = new(Student)    //安全,断言失败,也不会panic,只是ok的值为false    s, ok := i2.(Student)    if ok {        fmt.Println(s)    }}

断言其实还有另一种形式,就是用在利用 switch语句判断接口的类型。每一个case会被顺序地考虑。当命中一个case 时,就会执行 case 中的语句,因此 case 语句的顺序是很重要的,因为很有可能会有多个 case匹配的情况。

示例代码如下:

switch ins:=s.(type) {    case Triangle:        fmt.Println("三角形。。。",ins.a,ins.b,ins.c)    case Circle:        fmt.Println("圆形。。。。",ins.radius)    case int:        fmt.Println("整型数据。。") }

以上示例代码已归档到Github,欢迎下载学习:https://github.com/Scoefield/gokeyboardman/tree/main/gointerface

本次有关Golang的接口介绍就到这里,感谢您的阅读,如有疑问或意见请及时反馈给我们。


推荐阅读:

Golang之方法

作者: weixin_39832348
链接: https://blog.csdn.net/weixin_39832348/article/details/111248123?ops_request_misc=%7B%22request%5Fid%22%3A%22161130794616780271535762%22%2C%22scm%22%3A%2220140713.130102334.pc%5Fblog.%22%7D&request_id=161130794616780271535762&
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
到此这篇关于“golang 接口_Golang之接口”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:

登录查看全部

参与评论

评论留言

还没有评论留言,赶紧来抢楼吧~~

手机查看

返回顶部

给这篇文章打个标签吧~

棒极了 糟糕透顶 好文章 PHP JAVA JS 小程序 Python SEO MySql 确认