zoukankan      html  css  js  c++  java
  • Go与接口:实现接口的条件

    接口类型变量

    Go是强类型语言,你不能将整数值赋值给浮点型变量。同样,也不能将没有实现接口的类型值赋值给接口类型变量。

    // 1.定义变量是接口类型
    var w io.Writer
    // 2.将具体类型的值 赋值给这个变量, 要求这个具体类型实现了接口的所有方法
    w = os.Stdout
    w = new(bytes.Buffer)
    w = time.Second         // compile error: time.Duration 没有
    
    var rwc io.ReadWriteCloser
    rwc = os.Stdout
    rwc = new(bytes.Buffer)  // compile error: *bytes.Buffer lacks Close method
    
    
    // 等式右边是接口类型
    w = rwc
    rwc = w     // compile error: io.Writer lacks Close method
    

    关于一个类型持有一个方法的规则

    • T类型的值不持有*T指针的方法
    • *T指针的值持有T类型的方法

    所以可能会有*T指针值可以赋值为某接口类型变量而T类型的值不可以的情况

    type myWriter struct {}
    
    func (m *myWriter) Write(p []byte) (n int, err error) {
        return
    }
    
    func main() {
        var w io.Writer
        w = myWriter{}      // compile error: Cannot use 'myWriter{}' (type myWriter) as the type io.Writer Type does not implement 'io.Writer' as the 'Write' method has a pointer receiver
        w = &myWriter{}     // OK
    }
    

    接口类型封装和隐藏具体类型和它的值

    接口变量会限制自己只能调用接口类型声明的方法,即便该变量被赋予的值原本有其他方法和成员变量,也无法调用

    type myWriter struct {
        scope string
    }
    
    func (m *myWriter) Write(p []byte) (n int, err error) {
        return
    }
    
    func (m *myWriter) Func() {
    	return
    }
    
    func main() {
        my := &myWriter{"cn"}
        fmt.Println(my.scope)   // OK
        my.Func()               // Ok
        var w io.Writer
        w = my
        fmt.Println(w.scope)    // compile error: w.scope undefined
        w.Func()                // compile error: w.Func undefined
    }
    

    这样的限定就像是对实参进行了一层安全包装,函数内部只知道实参是接口类型,并不知道其他的信息,也无法访问。

    从之前的例子可以看到,大接口变量可以被赋值给小接口,被赋值后小接口也只能调用小接口的方法。

    空接口存在的意义

    空接口(interface{})即没有声明任何方法的接口。因为它什么都没有,所以它可以成为任何。

    package main
    
    import (
    	"bytes"
    	"fmt"
    )
    
    func emptyInterfaceIsAny() {
        var any interface{}
        any = true
        fmt.Println(any)
        any = 12.34
        fmt.Println(any)
        any = "hello"
        fmt.Println(any)
        any = map[string]int{"one": 1}
        fmt.Println(any)
        any = new(bytes.Buffer)
        fmt.Println(any)
        }
    

    这很有用,fmt.Println方法就是通过定义参数是空接口类型,才能接收任务类型的实参传递

    package main
    
    import "fmt"
    
    func printlnArgsIsEmptyInterface() {
    	fmt.Println(1, "hello", []string{"world"})  // 1 hello [world]
    }
    

    合理定义接口

    接口是对一些有着相同属性实体抽象。那对一些相同属性定义是仁者见仁智者见智,评判抽象的好与坏的标准即:这个接口类型的使用者是否舒服、被使用的次数多不对。
    文中展示的例子是对数字文化产品(如:音乐、电影和书籍)的抽象。

    其中对音乐和电影抽象出的Streamer值得思考

    type Streamer interface {
        Stream() (io.ReadCloser, error)
        RunningTime() time.Duration
        Format() string
    }
    

    每个具体类型基于他们实现接口声明的所有方法隐式地实现了接口。在Go语言中我们可以在需要的时候定义一个新的抽象或者特定特点的组,而不需要修改具体类型的定义。

  • 相关阅读:
    php多态
    ssl certificate problem: self signed certificate in certificate chain
    test plugin
    open specific port on ubuntu
    junit vs testng
    jersey rest service
    toast master
    use curl to test java webservice
    update folder access
    elk
  • 原文地址:https://www.cnblogs.com/Zioyi/p/14845089.html
Copyright © 2011-2022 走看看