interface接口
接口的概念,接口用于定义对象的行为。实现这种行为(方法或者函数)的细节由对来来决定。
在Go语言中,接口时一组方法签名,接口指定了类型应该具有的方法,类型决定了如何实现这些方法。
Go语言的类型都是隐式实现接口的。任何定义了接口中所有方法的类型都被称为隐式地实现了该接口
package main
import "fmt"
type phone interface {
call()
}
type Iphone struct {
}
type Huawei struct {
}
func (huawei Huawei)call() {
fmt.Println("我用的华为")
}
func (apple Iphone)call() {
fmt.Println("我用的苹果")
}
func main() {
//定义接口变量
var phone1 phone
phone1=new(Huawei)
fmt.Printf("%T,%v,%p\n",phone1,phone1,&phone1)
phone1.call()
phone1=Huawei{}
fmt.Printf("%T,%v,%p\n",phone1,phone1,&phone1)
phone1.call()
phone1=new(Iphone)
fmt.Printf("%T,%v,%p\n",phone1,phone1,&phone1)
phone1.call()
phone1=Iphone{}
fmt.Printf("%T,%v,%p\n",phone1,phone1,&phone1)
phone1.call()
}
/*
*main.Huawei,&{},0xc000038240
我用的华为
main.Huawei,{},0xc000038240
我用的华为
*main.Iphone,&{},0xc000038240
我用的苹果
main.Iphone,{},0xc000038240
我用的苹果
Process finished with the exit code 0
*/
大黄鸭duck typing
go没有implements或extends关键字,这类编程语言叫做duck typing编程语言
1、大黄鸭不是鸭子,没有生命
2、duck typing
duck typing是描述事物的外部行为而非内部结构。“一只鸟走起来像鸭子,叫起开像鸭子,那么这只鸟可以被称为鸭子。”
3、duck typing编程语言
使用duck typing 的编程语言往往被归类为“动态类型语言。”或者“解释型语言”,如python,JavaScript,ruby。而duck typing 编程语言被归为"静态类型语言".C/C++ 、Java
4、非duck typing编程语言
以Java为例,一个类必须显式声明"类实现了某个接口",然后才能用在这个接口可以使用的地方。如果有一个第三方Java库,这个库中的某个类没有声明它实现了某个接口。那么即使这个类真的有哪些接口中的方法,也不能把这个类用在那些需要用到接口的地方。但在duck typing编程语言中就可以这样做,因为它不要求一个类显示声明它实现了某个接口
5、动态类型语言的有缺点
动态类型语言有很多好处,python写起来很快。但是缺陷是需要运行时才发现,相反,静态类型语言往往编译时就发现这类错误:如果某个变量的类型没有显示地声明实现了某个接口。那么,这个变量就不能用在一个要求实现这个接口的地方。
第一、结构体类型T不需要显示地声明它实现了接口I,只要类型T实现了接口I规定地所有方法,它就自动地实现了接口I,这样动态类型语言一样省了很多代码,少了许多限制。
第二、将结构体类型的变量显式或者隐式地转换为接口I类型的变量i。这样就可以和其他静态类型语言一样,在编译时检查参数的合法性。
duck Typing Sample
package main
import "fmt"
type ISayHello interface {
SayHello() string
}
type duck struct {
name string
}
type persons struct {
name string
}
//这里就是duck typing的具体表现
func (d duck)SayHello() string {
return d.name+"叫:gagaga!"
}
//这里就是duck typing的具体表现
func (p persons)SayHello() string {
return p.name+"说:Hello!"
}
func main() {
//定义实现接口地对象
duck:=duck{"小黄鸭"}
person:=persons{"JackMa"}
fmt.Println(duck.SayHello())
fmt.Println(person.SayHello())
fmt.Println("------------------------")
//定义接口类型的变量
var i ISayHello
i=duck
fmt.Printf("%T,%v,%p\n",i,i,&i)
fmt.Println(i.SayHello())
i=person
fmt.Printf("%T,%v,%p\n",i,i,&i)
fmt.Println(i.SayHello())
}
/*
小黄鸭叫:gagaga!
JackMa说:Hello!
------------------------
main.duck,{小黄鸭},0xc000038260
小黄鸭叫:gagaga!
main.persons,{JackMa},0xc000038260
JackMa说:Hello!
Process finished with the exit code 0
*/
怎么说呢,Duck Typing就是将对象的方法和其继承的类进行了解偶,程序判断一个对象是声明并不是通过它的数据类型定义来判断的,而是判断它是否满足了某些特定的方法和属性定义,以此加大了编程的灵活度 —— 虽然我不继承自某个类,但我依然可以完成某些工作(实现某些函数和方法)
多态
如果有几个相似而不完全相同的对象,有时人们要求在向它们发出同一个消息时,它们的反应各不相同,分别执行不同的操作
空接口
空接口就是没有任何方法。任意类型都可以实现该接口。空接口这样定义:
interface{}
接口对象转换
package main
import (
"fmt"
"math"
)
//定义接口
type shape interface {
perimeter() float64
area() float64
}
type rectangles struct {
a,b float64
}
type triangles struct {
a,b,c float64
}
type circles struct {
radius float64
}
//定义实现接口方法
func (r rectangles) perimeter() float64 {
return (r.a+r.b)*2
}
func (r rectangles) area() float64 {
return r.a*r.b
}
func (t triangles) perimeter() float64 {
return t.a+t.b+t.c
}
//三角形知道三边求面积,根据海伦公式
func (t triangles) area() float64 {
p:=(t.a+t.b+t.c)/2
ret:=math.Sqrt(math.Abs(p*(p-t.a)*(p-t.b)*(p-t.c)))
return ret
}
func (c circles ) perimeter() float64 {
return math.Pi*c.radius*2
}
func (c circles) area() float64{
return math.Pi*c.radius*c.radius
}
func main() {
r1:=rectangles{3,4}
t1:=triangles{3,4,5}
c1:=circles{10}
fmt.Println(r1.perimeter()) //14
fmt.Println(r1.area()) //12
fmt.Println(t1.perimeter()) //12
fmt.Println(t1.area()) //6
fmt.Println(c1.perimeter()) //62.83185307179586
fmt.Println(c1.area()) //314.1592653589793
}