美文网首页
Go中的接口

Go中的接口

作者: authetic_x | 来源:发表于2019-06-17 10:14 被阅读0次

    一个接口类型定义了许多行为,每个函数代表一种行为,一个实现了这些方法的具体类型就是这个接口类型的实例。

    实现接口

    如果一个类型实现了一个接口需要的所有方法,那么该类型就实现了这个接口。Go的程序员经常会简要的把一个具体的类型描述成一个特定的接口类型。如:

    var w io.Writer
    w = os.Stdout           // OK: *os.File has Write method
    w = new(bytes.Buffer)   // OK: *bytes.Buffer has Write method
    w = time.Second         // compile error: time.Duration lacks Write method
    

    对于每一个命名过的具体类型T;它一些方法的接收者是类型T本身然而另一些则是一个*T的指针。在T类型的参数上调用一个*T的方法是合法的,只要这个参数是一个可寻址变量,编译器会帮我们做隐式转换。但这仅仅是一个语法糖:T类型的值不拥有所有*T指针的方法,那这样它就可能只实现更少的接口。注意:我们不能在不能寻址的值上调用调用指针定义的方法

    type IntSet struct { /* ... */ }
    func (*IntSet) String() string
    var _ = IntSet{}.String() // compile error: String requires *IntSet receiver
    

    然而,由于只有*IntSet类型有String方法,所以也只有*IntSet类型实现了fmt.Stringer接口:

    var _ fmt.Stringer = &s // OK
    var _ fmt.Stringer = s  // compile error: IntSet lacks String method
    

    接口的值

    概念上讲一个接口的值由两个部分组成,一个具体的类型和那个类型的值。当一个接口被声明时,它被初始化为零值,即它的类型和值的部分都是 nil,如:var w io.Writer
    接口值可以使用==和!=来进行比较。两个接口值相等仅当它们都是nil值或者它们的动态类型相同并且动态值也根据这个动态类型的==操作相等。因为接口值是可比较的,所以它们可以用在map的键或者作为switch语句的操作数。如果动态类型的值不可比较,那么会比较失败并且 panic

    包含nil指针的接口

    一个不包含任何值的nil接口值和一个刚好包含nil指针的接口值是不同的。

    func test(debug bool) io.Writer{
        var out *bytes.Buffer
        if debug {
            out = new(bytes.Buffer)
            out.Write([]byte("Done"))
        }
        return out
    }
    

    上述程序会引发 panic,panic: nil pointer dereference
    原因是out的类型值为非空,只是包含了一个nil指针,所以判断里的语句违反了(*bytes.Buffer).Write方法的接收者非空的隐含先觉条件,正确的做法是将 out 声明改为 *io.Writer

    类型断言

    类型断言是一个使用在接口上的操作。一个类型断言检查它操作对象的动态类型是否和断言的类型匹配。

    var w io.Writer
    w = os.Stdout
    f := w.(*os.File)      // success: f == os.Stdout
    c := w.(*bytes.Buffer) // panic: interface holds *os.File, not *bytes.Buffer
    

    断言类型也可以是一个接口类型

    var w io.Writer
    w = os.Stdout
    rw := w.(io.ReadWriter) // success: *os.File has both Read and Write
    w = new(ByteCounter)
    rw = w.(io.ReadWriter) // panic: *ByteCounter has no Read method
    

    当我们对一个接口值的动态类型不是很确定时,我们会用类型断言去检验它是否是某个特定类型

    var w io.Writer = os.Stdout
    f, ok := w.(*os.File)      // success:  ok, f == os.Stdout
    b, ok := w.(*bytes.Buffer) // failure: !ok, b == nil
    
    if f, ok := w.(*os.File); ok {
        // ...use f...
    }
    

    相关文章

      网友评论

          本文标题:Go中的接口

          本文链接:https://www.haomeiwen.com/subject/vekofctx.html