<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] # 接口 謹記:接口(interface)是一種類型,一種抽象的類型 ## 接口類型 接口是一種由程序員來定義的類型,一個接口類型就是一組方法的集合,它規定了需要實現的所有方法。 ### 接口的定義 每個接口類型由任意個方法簽名組成,格式如下: ``` type interface_name interface{ function_name1( [param] ) [return_values] function_name2( [param] ) [return_values] … } ``` 其中: * type關鍵字表示要自定義類型; * interface_name是自定義的接口名;interface表示接口類型;由大括號包裹的部分定義了要被實現方法,一個接口中可以同時存在一個或多個方法。 * function_name是方法名;params是方法所需的參數,return_values是方法的返回值。params和return_values可以省略,也可以存在一個或多個。 * 在為接口命名時,一般會在單詞后面加上er后綴 eg: ``` type personer interface{ … } ``` ## 接口的實現 接口就是規定了一個**需要實現的方法列表**,在 Go 語言中一個類型只要實現了接口中規定的所有方法,那么我們就稱它實現了這個接口。 ``` type player interface{ play() } type jinglecat struct{} func (j *jinglecat) play(){ fmt.Println("播放了3集~") } ``` 因為`player`接口只包含一個`play`方法,所以只需要給`jinglecat`結構體添加一個`play`方法就可以滿足`player`接口的要求,此時就可以說是實現了接口 ### 為什么要使用接口 ``` type jinglecat struct{} func (j *jinglecat) play(){ fmt.Println("小叮當播放了3集~") } type naruto struct{} func (n *naruto) play(){ fmt.Println("火影播放了3集~") } func main(){ cat := new(jinglecat) cat.play() //小叮當播放了3集~ nar := new(naruto) nar.play() //火影播放了3集~ } ``` 還有很多的動畫片也播放3集了那就需要寫很多的以上重復代碼,那么,定義一個接口 ``` type player interface{ play() } func comicPlay(p player) { ? ? p.play() } func main() { var cater player cater = new(jinglecat) comicPlay(cater) //小叮當播放了3集~ cater = &naruto{} comicPlay(cater)//火影播放了3集~ } ``` 就相當于面向接口編程,根本不關心某個類型具體的play怎么實現,我們關心play能不能正常實現 ## 值接收者和指針接收者 ### 值接收者實現接口 ``` type player interface{ play() } type jinglecat struct{} func (j jinglecat) play(){ fmt.Println("小叮當播放了3集~") } type naruto struct{} func (n *naruto) play(){ fmt.Println("火影播放了3集~") } func main(){ cat := jinglecat{} cat.play() //小叮當播放了3集~ } ``` ### 指針接收者實現接口 ``` type player interface{ play() } type naruto struct{} func (n *naruto) play(){ fmt.Println("火影播放了3集~") } func main(){ nar := new(naruto) //或者&naruto{} nar.play() //火影播放了3集~ } ``` 區別: * 在接口背景下,對于值接收者實現的接口,無論使用值類型還是指針類型都沒有問題,但是當是指針類型時候只能是指針。 * 在非接口情況下,值類型和指針類型的方法,可以互相調用 ## 類型與接口的關系 ### 一個類型實現多個接口 ``` type mover interface { move() } type sayer interface { say() } type cat struct { Name string } func (c *cat) move() { ? ? fmt.Printf("%s 咔咔咔跑 \n", c.Name) } func (c *cat) say() { ? ? fmt.Printf("%s wawa叫 \n", c.Name) } func main() { var d1 mover x := &cat{ Name: "叫我小叮當啊", ? ? } d1 = x ? ? d1.move() //叫我小叮當啊 咔咔咔跑 var d2 sayer d2 = x ? ? d2.say() //叫我小叮當啊 wawa叫 } ``` ### 多種類型實現同一接口 ``` type mover interface { move() } type cat struct { name string } func (c *cat) move() { fmt.Printf("%s 咔咔跑 \n", c.name) } type car struct { name string } func (c *car) move() { fmt.Printf("%s 嗚嗚跑~ \n", c.name) } func main() { var moveType mover dog := &cat{ name: "叫我小叮當啊", } moveType = dog moveType.move()//叫我小叮當啊 咔咔跑 car := &car{ name: "火車", } moveType = car moveType.move()//火車 嗚嗚跑~ } ``` ### 嵌入結構體實現接口 ``` type personer interface { eat() drink() } type man struct { sex string } func (m *man) eat() { fmt.Printf("%s 會吃肉 \n", m.sex) } type women struct { name string man } func (w *women) drink() { fmt.Printf("名字是%s 的 %s 還能喝酒\n", w.name, w.sex) } func main() { var person personer women := &women{ name: "露娜", man: man{ sex: "女人", }, } person = women person.eat() person.drink() } ``` ### 接口互相嵌套 ``` type personer interface { drinker eater } type drinker interface { drink() } type eater interface { eat() } type wan struct { name string } func (w *wan) eat() { fmt.Printf("%s 賊能吃\n", w.name) } func (w *wan) drink() { fmt.Printf("%s 還賊能喝\n", w.name) } func main() { var newperson personer wan := &wan{ name: "叫我小叮當啊", } newperson = wan newperson.eat() newperson.drink() } ``` ## 空接口 ### 空接口的定義 空接口是指沒有定義任何方法的接口類型。因此任何類型都可以視為實現了空接口。也正是因為空接口類型的這個特性,空接口類型的變量可以存儲任意類型的值。 ``` // Any 不包含任何方法的空接口類型 type Any interface{} func main() { var x Any x = "你好" // 字符串型 fmt.Printf("type:%T value:%v\n", x, x) x = 100 // int型 fmt.Printf("type:%T value:%v\n", x, x) x = true // 布爾型 fmt.Printf("type:%T value:%v\n", x, x) } ``` 通常我們在使用空接口類型時不必使用`type`關鍵字聲明,可以像下面的代碼一樣直接使用`interface{}`。 ``` var x interface{} // 聲明一個空接口類型變量x ``` ### 空接口的應用 #### 空接口作為函數的參數 使用空接口實現可以接收任意類型的函數參數。 ``` // 空接口作為函數參數 func show(a interface{}) { fmt.Printf("type:%T value:%v\n", a, a) } ``` #### 空接口作為map的值 使用空接口實現可以保存任意值的字典。 ``` var studentInfo = make(map[string]interface{}) studentInfo["name"] = "叫我小叮當啊" studentInfo["age"] = 18 studentInfo["gener"] = "男" fmt.Println(studentInfo) ``` ## 接口值 由于接口類型的值可以是任意一個實現了該接口的類型值,所以接口值除了需要記錄具體**值**之外,還需要記錄這個值屬于的**類型**。也就是說接口值由“類型”和“值”組成,鑒于這兩部分會根據存入值的不同而發生變化,我們稱之為接口的`動態類型`和`動態值`。 ![](https://img.kancloud.cn/73/19/73190886381a4c5257c6a84596df3393_454x278.png) ``` type Mover interface { Move() } type Dog struct { Name string } func (d *Dog) Move() { fmt.Println("狗在跑~") } type Car struct { Brand string } func (c *Car) Move() { fmt.Println("汽車在跑~") } ``` 創建一個`Mover`接口類型的變量`m`。 ``` var m Mover ``` 此時,接口變量`m`是接口類型的零值,也就是它的類型和值部分都是`nil`,如圖 ![](https://img.kancloud.cn/92/53/9253a41b2b2cd12e53cd817ee0b6f331_420x277.png) 可以使用`m == nil`來判斷此時的接口值是否為空。 ``` fmt.Println(m == nil) // true ``` **注意:**我們不能對一個空接口值調用任何方法,否則會產生panic。 ``` m.Move() // panic: runtime error: invalid memory address or nil pointer dereference ``` 我們給接口變量`m`賦值為一個`*Car`類型的值。 ``` m = new(Car) ``` 接口值的動態類型為`*Car`,動態值為`nil` ![](https://img.kancloud.cn/53/5e/535e9cf5d4df54e0a5a381cb6f6b9bc9_845x304.png) **注意:**此時接口變量`m`與`nil`并不相等,因為它只是動態值的部分為`nil`,而動態類型部分保存著對應值的類型。 **接口值是支持相互比較的,當且僅當接口值的動態類型和動態值都相等時才相等。有兩種數據是無法比較的,它們是:Map和Slice** ## 類型斷言 格式: ``` value, ok := x.(T) ``` 其中: * x:表示接口類型的變量 * T:表示斷言`x`可能是的類型。 ``` type Cube struct { length float64 } func (c *Cube) cubeVolume() float64 { return math.Pow(c.length, 3) } type Cuboid struct { length float64 width float64 height float64 } func (c *Cuboid) CuboidVolume() float64 { return c.height * c.length * c.width } type Cylinder struct { diameter float64 height float64 } func (c *Cylinder) CylinderVolume() float64 { return math.Pi * math.Pow((c.diameter/2), 2) * c.height } func calcSize(material interface{}) float64 { switch data := material.(type) { case Cube: return data.cubeVolume() case Cuboid: return data.CuboidVolume() case Cylinder: return data.CylinderVolume() default: return 0 } } func main() { countSize := 0.0 var sizeSlice []interface{} sizeSlice = append(sizeSlice, Cube{length: 12}) sizeSlice = append(sizeSlice, Cuboid{length: 12.0, width: 4.5, height: 3.0}) sizeSlice = append(sizeSlice, Cylinder{height: 3.0, diameter: 6.5}) for _, value := range sizeSlice { countSize += calcSize(value) } fmt.Println(countSize) } ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看