4,接口的学习

变量和实例

空接口

4.1 基本概念

4.1.1 接口声明

接口定义大括号内可以是方法声明的集合,也可以嵌入另一个接口类型匿名字段,还可以是两者混合。

type Reader interface {

    Read(p []byte) (n int, err error)

}

type Writer interface {

    Write(p []byte) (n int, err error)

}

//如下三种声明时等价的,最终的展开模式都是第3种格式

type ReadWriter interface {

    Reader

    Writer

}

type ReadWriter interface {

    Reader

    Write(p []byte) (n int, err error)

}

type ReadWriter interface {

    Read(p []byte) (n int, err error)

    Write(p []byte) (n int, err error)

}

方法声明

方法声明=方法名+方法签名

声明新接口类型的特点

1) 接口命名一般以 “er” 结尾

2)接口定义的内部方法声明不需要 func 引导

3) 在接口定义中,只有方法声明没有方法实现

4.1.2 接口初始化

接口只有被初始化为具体的类型才有意义。

实例赋值接口

接口变量赋值接口变量

file, _ := os.OpenFile("notes.txt", os.O)RDWR | os.O_CREATE, 0755)

var rw io.ReadWriter = file

// io.ReadWriter 接口可以直接赋值给 io.Writer接口变量

var w io.Writer = rw

4.1.3 接口方法调用

接口方法调用最终地址是在运行期决定的,将具体类型变量赋值给接口后,会使用具体类型的方法指针初始化接口变量,当调用接口变量的方法时,实际上是间接地调用实例的方法。

接口方法调用不是一种一直接的调用,有一定的运行时开销。

type Printer interface {

    Print()

}

type S struct {}

func (s S) Print() {

    println("print")

}

func main() {

    var i Printer

    // 没有初始化的接口调用其方法会产生panic

    // i.Print()

    // 必须初始化

    i = S {}

    i.Print()

}

4.1.4 接口的动态类型和静态类型

动态类型

静态类型

4.2 接口运算

基于接口编程是Go语言编程的基本思想

4.2.1 类型断言

接口断言的两种语法表现

o := i.(TypeName)

如果不满足程序会抛panic。例如:

type Inter interface {

    Ping()

    Pang()

}

type Anter interface {

    Inter

    String()

}

type St struct {

    Name string

}

func (St) Ping() {

    println("ping")

}

func (*St) Pang() {

   println("pang")

}

func main() {

    st := &St { "andes" }

    var i interface {} =  st

    // 判断i绑定的实例是否实现了接口类型Inter

    o := i.(Inter)

    o.Ping()

    o.Pang()

    // 如下语句会引发panic, 因为 i 没有实现接口 Anter

    // p := i.(Anter)

    // p.String()

    // 判断 i 绑定的实例是否就就是具体类型St

    s := i.(*St)

    fmt.Printf("%s", s.Name)

}

   comma, ok 表达式模式如下:

    if o, ok := i.(TypeName)l ok {

    }

4.2.2 类型查询

接口查询有两层语义,

1是查询一个接口变量底层绑定的底层变量的具体类型是什么

2是查询接口变量绑定的底层变量是否还实现其他接口

switcg v := i.(type)

case type1:

    xxxx

case type2:

    xxxx

default:

    xxxx

1) i 必须是接口类型

var i io.Reader

switch v := i.(type) { // 此处i是未初始化的接口变量,所以v为nil

case nil:

    fmt.Printf("%T\n", v) // nil

default:

    fmt.Printf("default")

 

}

 2)case 字句后面可以跟非接口类型名,也可以跟接口类型名,匹配是按照case子句的顺序进行的。

4.2.3 接口优点和使用形式

接口优点

1)解耦

2)实现泛型

接口使用形式

1)作为结构内嵌字段

2)作为函数或者方法的形参

3)作为函数或方法的返回值

4)作为其他接口定义的嵌入字段

 

4.3 空接口

没有任何方法的接口 ,我们称为空接口。类似java中的Object

4.3.2 空接口的用途

空接口和泛型

Go语言没有泛型,如果一个函数需要接口任意类型的参数 ,则参数类型可以使用空接口类型

// 典型的就是fmt标准表 里面的print函数

func Fprint(w io.Writer, a ...interface{}) (n int, err error)

空接口和反射

4.3.3 空接口和nil

空接口不是真的为空,接口有类型和值两个概念。

type Inter interface {

    Ping()

    Pang()

}

type St struct {}

func (St) Ping () {

    println("ping")

}

func (*St) Pang() {

    println("pang")

}

func main() {

    var st *St = nil

    var it Inter = st

    fmt.Printf("%p\n", st)

    fmt.Printf("%p\n", it)

    if it !=nil {

        it.Pang()

        // 下面的语句会导致panic

        // 方法转换为函数调用,第一个参数是St类型,由于*St是nil, 无法获取指针所指的对象值,所以导致panic  (这里没有明白是啥,等我先把这个搞清楚明白再继续往下写。134)

       //  it.Ping()

    }

 

}

4.4 接口内部实现

4.4.1 数据结构

4.4.2 接口调用过程分析

4.4.3 接口调用的代价

4.4.4 空接口数据结构

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值