golang接口

7.接口

接口多个方法声明集合,代表一种调用契约。

目标类型方法包含接口声明的全部方法,就视为实现该接口,无需显示声明

接口:不能有字段

只能声明方法,不能实现

可嵌入其他接口

1.
//匿名接口的使用
type N struct{}
func (N) test() {}
​
// -------------------------
​
type node struct {
    value interface {
        test()
    }
}
​
// -------------------------
​
func main() {
    var t interface {
        test()
    } = N{}
    
    n := node{ value: t }
    n.value.test()
}
2.空接口

空接口可被赋值任何对象

type Xer interface {
    toString() string
}
​
// -------------------------
​
type N struct {
    x int
}
​
func (n N) toString() string { 
    return strconv.Itoa(n.x)
}
​
// -------------------------
​
func main() {
    n := N{ 100 }
    var x Xer = n   // copy n的副本被创建并且赋值给x,x与n是独立的!!!
​
    n.x = 200
​
    println(n.toString())  // 200
    println(x.toString())  // 100
}
3.匿名嵌入

无法循环嵌入

签名(函数名称,接受阐述,返回参数相同)要相同,golang不可重载(不可以有相同名称,但不同参数的函数

type Aer interface {
    Test()
}
​
type Ber interface {
    ToString(string) string
}
​
// -------------------------
​
type Xer interface {
    Aer
    Ber                            // 嵌入接口有相同声明。
​
    ToString(s string) string      // 签名相同(并集去重)。
​
    // ToString() string           // 不允许重载(签名不同)。
    // ~~~~~~ duplicate method
​
    Print()
}
​
// -------------------------
​
type N struct{}
func (N) ToString(string) string { return "" }
func (N) Test() {}
func (N) Print() {}
​
// -------------------------
​
func main() {
    i := Xer(N{})
    t := reflect.TypeOf(i)
​
    for i := 0; i < t.NumMethod(); i++ {
        fmt.Println(t.Method(i))
    }
}
​
/*
​
   Print:  func(main.N)
    Test:  func(main.N)
ToString:  func(main.N, string) string
​
*/
4.类型转换

超集接口可隐式转换为子集(反之不行

雨痕大佬的代码:将Xer转换为Aer,反之则不行

type Aer interface {
    toString(string) string
}
​
// -------------------------
​
type Xer interface {
    // Aer
​
    test()
    toString(string) string
}
​
// -------------------------
​
type N struct{}
func (*N) test() {}
func (N) toString(s string) string { return s }
​
// -------------------------
​
func main() {
    var x Xer = &N{}     // super
    var a Aer = x        // sub
​
    a.toString("abc")
​
    // var x2 Xer = a
    //              ~ Aer does not implement Xer (missing test method)
    
    // x2 := Xer(a)
    //           ~ Aer does not implement Xer    
}

如何判断接口的原始类型

将接口还原为原始类型

func main() {
    var x Xer = &N{}     // super
    var a Aer = x        // sub
​
    // 原始类型。
    n, ok := a.(*N)
    fmt.Println(n, ok)   // true
​
    // 接口。
    x2, ok := a.(Xer)
    fmt.Println(x2, ok)  // true
}

空接口的还原

func main() {
    var e any = (*int)(nil) // !!!
    _, ok := e.(*int)
​
    println(ok)  // true
}

可以利用switch在多种类型中进行还原,如此空接口有更多发挥空间

func main() {
    var i any = &N{}
​
    switch v := i.(type) {
    case nil: 
    case *int:
    case func()string:
    case *N: fmt.Println(v)
    case Xer: fmt.Println(v)
    default:
    }
}
​

无法使用fallthrough(fallthrough 是 Go 编程语言中的一个关键字,用于 switch 语句中。当在一个 case 中使用 fallthrough 时,它会导致控制流传递到下一个 case 标签,无论该 case 的条件是真还是假。)

    var i any = &N{}
​
    switch v := i.(type) {   // v declared but not used
    case *N: fallthrough     // fallthrough statement out of place
    default:
    }
}
5.接口比较

可以作==,!=的运算

(引用类型无法比较

比较的时候,相同的实现相等,超集与子集相等(

当一个接口的itab(一种内部数据结构,用于支持接口类型的运行时类型信息,记录了一个接口类型和一个具体类型之间的关联信息)与data都为nil,接口为nil

7.1接口的实现

// runtime/runtime2.go
​
type iface struct {
    tab  *itab            // 类型和方法表。
    data unsafe.Pointer   // 目标对象指针。
}
​
type itab struct {
    inter *interfacetype  // 接口类型。  
    _type *_type          // 目标类型。
    hash  uint32
    fun   [1]uintptr      // 方法表。 offset: 24, 0x18
}

利用方法表进行映射,由接口的函数映射到实现的函数

7.2trick

让编译器检查,确保类型实现了指定接口

利用实现接口的方式将函数转换为接口类型,如何使用接口来实现多态

type FuncString func() string
​
func (f FuncString) String() string {
    return f()
}
​
// ----------------------------------
​
func main() {
​
    f := func() string {
        return "hello, world!"
    }
​
    var t fmt.Stringer = FuncString(f)
    fmt.Println(t)
}

(因为 string实现了String方法)

  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值