zoukankan      html  css  js  c++  java
  • go入门6 -- 接口

    接口是Go类型语言中数据类型的关键。接口是一个或多个方法签名的集合,对于任何类型,只要拥有以这个接口对应的全部方法,就说明该类型实现了这个接口,无需在该类型上显示添加接口声明。

    对应的方法是指具有相同的名称,参数列表,以及返回值。除此之外,该类型还可以有其他。

    说一下接口的特点:

    • 接口命名一般习惯以er结尾,结构体;
    • 接口只有方法的签名,并非是实现了某方法
    • 接口没有数据字段
    • 在接口中可以嵌套其他接口
    • 类型可以实现多个接口
    type User struct {
        id   int
        name string
    }
    
    func (u *User) TellId() {
        fmt.Println(u.id)
    }
    
    func (u *User) String() string {
        return fmt.Sprintf("user:%d", u.id)
    }
    
    func (u *User) TellName() {
        fmt.Println(u.name)
    }
    
    type Stringer interface {
        String() string
    }
    
    type Printer interface {
        TellId()
    }
    type UUer interface {
        Printer
        TellName()
    }
    
    func main() {
        var user = &User{10, "goland"}
        var user1 Printer = &User{1, "tom"}
        var user2 Stringer = &User{2, "jason"}
        var user3 UUer = &User{3, "jack ma"}
        user1.TellId()              // 1
        fmt.Println(user2.String()) // user:2
        user3.TellId()              // 3
        //fmt.Println(user3.String()) // user3.String undefined (type UUer has no field or method String)
        fmt.Println(user.String()) // user:10
        user.TellId()              // 10
        user.TellName()            // goland
        //userToUUer := UUer(user)
        //userToUUer.String()  // userToUUer.String undefined (type UUer has no field or method String)
    }

    从上述栗子中可以看出,User实现了Stringer, Printer, UUer的所有接口,因此user的实例可以调用所有的方法,并且同时可以看出,接口是可以嵌套的

    另外可以看出超集接口可以转化为子集接口,反过来去不行,一旦转化为子集接口,则该类型只可以使用子集方法。

    空接口interfacr{} 没有任何方法和签名,这也就意味着任何类型都实现了空接口。

    我们可以利用interface进行接口类型判断,注意这个里面是不支持fallthrough。

    type User struct {
        id   int
        name string
    }
    
    func main() {
        var m interface{} = &User{1, "jack ma"}
        switch v := m.(type) {
        case nil:
            fmt.Println("nil")
        case fmt.Stringer:  // 因为User没有实现String()string方法,因为没实现这个接口
            fmt.Println("string", v)
        case func() string:
            fmt.Println("func")
        case *User:
            fmt.Println("User")
        default:
            fmt.Println("i do not know")
        }
    }// 最终打印User

    关于执行机制,接口对象由接口表(interface table)指针和数据指针组成,部分源码文件如下,根据 interface 是否含有方法,低层实现用了下述两个 struct 来进行表示, iface代表non-empty,这个里面包含实现的方法, eface代表是empty,就是里面不包含方法,这个编译器会自动帮助我们选择。从这里面可以看到,interface实际上有两个成员,tab和data,tab指向的是虚表,data则指向实际引用数据

    type iface struct {
        tab  *itab
        data unsafe.Pointer
    }
    
    type eface struct {
        _type *_type
        data  unsafe.Pointer
    }

    经过上述分析,我们就可以判定interface与nil的关系

    type State struct{}
    
    func testnil1(a, b interface{}) bool {
        return a == b
    }
    
    func testnil2(a *State, b interface{}) bool {
        return a == b
    }
    
    func testnil3(a interface{}) bool {
        return a == nil
    }
    
    func testnil4(a *State) bool {
        return a == nil
    }
    
    func testnil5(a interface{}) bool {
        v := reflect.ValueOf(a)
        return !v.IsValid() || v.IsNil()
    }
    
    func main() {
        var a *State
        fmt.Println(testnil1(a, nil)) // false
        fmt.Println(testnil2(a, nil)) // false
        fmt.Println(testnil3(a))      //false
        fmt.Println(testnil4(a))      // true
        fmt.Println(testnil5(a))      // true
    }

    interface{}一共包含两个指针,一个指向值的类型,另外一个指向值的类型,对一个interface{}类型的nil变量来说,它的两个指针都是0;但是var a *State传进去后,指向的类型的指针不为0了,因为有类型了, 所以比较为false。 interface 类型比较, 要是两个指针都相等, 才能相等。

  • 相关阅读:
    vue中dom元素和组件的获取
    Vue.js中父子组件之间的传值和传方法
    IDEA中的快捷键
    springmvc中使用controller时,跳转视图会带上外层的地址
    通配符的匹配很全面, 但无法找到元素 'mvc:annotation-driven' 的声明
    vue中的组件
    vuejs
    成员变量(实例变量)&局部变量&静态变量(类变量)的区别
    代码块
    重载&重写
  • 原文地址:https://www.cnblogs.com/yangshixiong/p/12133549.html
Copyright © 2011-2022 走看看