05.interface

[TOC]

一.接口基础

1.类型转换不适用于接口。
2.我们只能使用接口里面定义好的方法,未列出的不能使用。
3.类型断言像是说我知道这个变量使用接口类型Animal,但是我很确信这个Animal实际上就是Dog.
  #-----------------------------------------------------------------------
    package main

    import "fmt"

    type Animal interface{
        Eat()
    }

    type Dog string

    func (d Dog) Eat(){
        fmt.Println(d,"wang wang!")
    }

    func (d Dog) Run(){
        fmt.Println(d,"speed up!")
    }

    func main(){
        var a Animal = Dog("旺财")
        a.Eat()

        // interface里面我们只定义了Eat()方法,Dog对象里我们定义了Eat()/Run()方法,此时 我们直接调用Run方法,报错如下:
        // a.Run undefined (type Animal has no field or method Run)
        // a.Run()

        // 这里使用断言从接口里取回Dog对象的具体类型
        var d Dog = a.(Dog)
        d.Run()
    }
  #-----------------------------------------------------------------------
4.error类型像int或者string一样是一个“预定义标识符”,它不属于任何包。它是“全局块”的一部分,这意味着它在任何地方可用,不用考虑当前包信息。

5.Stringer接口
    - 允许任何类型决定在输出时如何展示。让其他类型满足Stringer接口很简单,只需要定义一个返回string类型的方法。
    - 只要是定义了符合stringer接口的方法,就会在执行的时候 直接被调用。
  #-----------------------------------------------------------------------
    package main

    import "fmt"

    type Gallons float64
    func (g Gallons) String() string{
        return fmt.Sprintf("%0.2f gal",g)
    }

    type Liters float64

    func (l Liters) String() string{
        return fmt.Sprintf("%0.2f L",l)
    }


    type Milliliters float64
    func (m Milliliters) String() string{
        return fmt.Sprintf("%0.2f mL",m)
    }


    type CoffeePot string

    func (c CoffeePot) String() string {
        return string(c)+"coffee pot"
    }

    func main(){
        coffeePot :=CoffeePot("华为牌")
        fmt.Println(coffeePot)

        // 自动调用String方法
        fmt.Println(Gallons(11.0202992))
        fmt.Println(Liters(11.0202992))
        fmt.Println(Milliliters(11.0202992))
    }
#-----------------------------------------------------------------------

6.接口特性
    - 接口定义只有方法
    - 接口是引用类型
    - 实例化时,接口不能直接使用变量,必须指向实现。
    - Golang没有严格的implement关键字。
    - 必须实现所有的接口方法,才叫实现接口,否则不算。
    - 必须实现所有的接口方法,才叫实现接口,不限类型。
    - 同一个对象可以实现多个接口。
    - 接口之间可以组合、嵌套(c=a+b+c,也可以c=ab+bc)- 空接口=any=黑盒子。

7.类型断言
    - interface{}可以容纳任何对象,因此从各种对象赋值给interface变量时可以无缝赋值。
    -interface{}重新赋值回特定的类型,无法直接赋值。
    - switch 方式
    - value,ok := i.(<type>)
8.对象or指针
    - 方法可以再对象上,也可以再对象指针上,在使用时,调用、功能有略微差异。
    - 定义在对象上的方法无法修改对象属性,定义在对象指针上的可以。
    - 对象上实现了接口的所有函数,才可以转为对应的接口对象,如果某些函数是在对象指针上,某些是在对象上,则只能用对象指针作为接口对象。
9.接口技巧
    - 接口的变更,不会带来编译失败,从而导致程序出现异常。

10.善用var _ int(接口) = &io{} //接口实例化
    package main

    import "fmt"

    // 强制实现Door接口里面的所有方法。
    var _ Door = &WoodDoor{}

    type WoodDoor struct {

    }

    func (g *WoodDoor) Unlock() {
        fmt.Println("WoodDoor unlock door。")
    }

    func (g *WoodDoor) Lock() {
        fmt.Println("WoodDoor unlock door。")
    }

    func (g *WoodDoor) Open(){
        fmt.Println("WoodDoor开门。")
    }
    func (g *WoodDoor) Close(){
        fmt.Println("WoodDoor关门。")
    }

11.面向接口编程
    - 面向接口编程是指在开发应用时,将执行细节和执行框架进行剥离,重点关注在定义模块、组件之间的交互、协助之上的接口定义与开发。

二.面向接口编程之-实战体脂计算器

(一).要求

1.体脂计算器可以接受终端录入。
2.体脂计算器可以接受从文件批量读取。
3.体脂计算器可以接受从身高体重测量器上读取。