<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國際加速解決方案。 廣告
                # 11.9 空接口 - [11.9.1 概念](#1191__1) - [\[\](https://github.com/Unknwon/the-way-to-go\_ZH\_CN/blob/master/eBook/11.9.md#1192-構建通用類型或包含不同類型變量的數組)11.9.2 構建通用類型或包含不同類型變量的數組](#httpsgithubcomUnknwonthewaytogo_ZH_CNblobmastereBook119md11921192__2) - [\[\](https://github.com/Unknwon/the-way-to-go\_ZH\_CN/blob/master/eBook/11.9.md#1193-復制數據切片至空接口切片)11.9.3 復制數據切片至空接口切片](#httpsgithubcomUnknwonthewaytogo_ZH_CNblobmastereBook119md11931193__3) - [11.9.4 通用類型的節點數據結構](#1194__4) - [11.9.5 接口到接口](#1195__5) ## 11.9.1 概念 **空接口或者最小接口** 不包含任何方法,它對實現不做任何要求: ``` type Any interface {} ``` 任何其他類型都實現了空接口(它不僅僅像 `Java/C#` 中 `Object` 引用類型),`any` 或 `Any` 是空接口一個很好的別名或縮寫。 空接口類似 `Java/C#` 中所有類的基類: `Object` 類,二者的目標也很相近。 可以給一個空接口類型的變量 `var val interface {}` 賦任何類型的值。 示例 11.8 empty\_interface.go: ``` package main import "fmt" var i = 5 var str = "ABC" type Person struct { name string age int } type Any interface{} func main() { var val Any val = 5 fmt.Printf("val has the value: %v\n", val) val = str fmt.Printf("val has the value: %v\n", val) pers1 := new(Person) pers1.name = "Rob Pike" pers1.age = 55 val = pers1 fmt.Printf("val has the value: %v\n", val) switch t := val.(type) { case int: fmt.Printf("Type int %T\n", t) case string: fmt.Printf("Type string %T\n", t) case bool: fmt.Printf("Type boolean %T\n", t) case *Person: fmt.Printf("Type pointer to Person %T\n", t) default: fmt.Printf("Unexpected type %T", t) } } ``` 輸出: ``` val has the value: 5 val has the value: ABC val has the value: &{Rob Pike 55} Type pointer to Person *main.Person ``` 在上面的例子中,接口變量 `val` 被依次賦予一個 `int`,`string` 和 `Person` 實例的值,然后使用 `type-swtich` 來測試它的實際類型。每個 `interface {}` 變量在內存中占據兩個字長:一個用來存儲它包含的類型,另一個用來存儲它包含的數據或者指向數據的指針。 例子 emptyint\_switch.go 說明了空接口在 `type-swtich` 中聯合 `lambda` 函數的用法: ``` package main import "fmt" type specialString string var whatIsThis specialString = "hello" func TypeSwitch() { testFunc := func(any interface{}) { switch v := any.(type) { case bool: fmt.Printf("any %v is a bool type", v) case int: fmt.Printf("any %v is an int type", v) case float32: fmt.Printf("any %v is a float32 type", v) case string: fmt.Printf("any %v is a string type", v) case specialString: fmt.Printf("any %v is a special String!", v) default: fmt.Println("unknown type!") } } testFunc(whatIsThis) } func main() { TypeSwitch() } ``` 輸出: ``` any hello is a special String! ``` **練習 11.9** simple\_interface3.go: 繼續 練習11.2,在它中添加一個 `gI` 函數,它不再接受 `Simpler` 類型的參數,而是接受一個空接口參數。然后通過類型斷言判斷參數是否是 `Simpler` 類型。最后在 `main` 使用 `gI` 取代 `fI` 函數并調用它。確保你的代碼足夠安全。 ## 11.9.2 構建通用類型或包含不同類型變量的數組 在 7.6.6 中我們看到了能被搜索和排序的 `int` 數組、`float` 數組以及 `string` 數組,那么對于其他類型的數組呢,是不是我們必須得自己編程實現它們? 現在我們知道該怎么做了,就是通過使用空接口。讓我們給空接口定一個別名類型 `Element`:`type Element interface{}` 然后定義一個容器類型的結構體 `Vector`,它包含一個 `Element` 類型元素的切片: ``` type Vector struct { a []Element } ``` `Vector` 里能放任何類型的變量,因為任何類型都實現了空接口,實際上 `Vector` 里放的每個元素可以是不同類型的變量。我們為它定義一個 `At()` 方法用于返回第 `i` 個元素: ``` func (p *Vector) At(i int) Element { return p.a[i] } ``` 再定一個 `Set()` 方法用于設置第 `i` 個元素的值: ``` func (p *Vector) Set(i int, e Element) { p.a[i] = e } ``` `Vector` 中存儲的所有元素都是 `Element` 類型,要得到它們的原始類型(unboxing:拆箱)需要用到類型斷言。TODO:The compiler rejects assertions guaranteed to fail,類型斷言總是在運行時才執行,因此它會產生運行時錯誤。 **練習 11.10** min\_interface.go / minmain.go: 仿照11.7中開發的 `Sorter` 接口,創建一個 `Miner` 接口并實現一些必要的操作。函數 `Min` 接受一個 `Miner` 類型變量的集合,然后計算并返回集合中最小的元素。 ## 11.9.3 復制數據切片至空接口切片 假設你有一個 `myType` 類型的數據切片,你想將切片中的數據復制到一個空接口切片中,類似: ``` var dataSlice []myType = FuncReturnSlice() var interfaceSlice []interface{} = dataSlice ``` 可惜不能這么做,編譯時會出錯: ``` cannot use dataSlice (type []myType) as type []interface { } in assignment ``` 原因是它們倆在內存中的布局是不一樣的(參考 [官方說明](http://golang.org/doc/go_spec.html))。 必須使用 `for-range` 語句來一個一個顯式地復制: ``` var dataSlice []myType = FuncReturnSlice() var interfaceSlice []interface{} = make([]interface{}, len(dataSlice)) for ix, d := range dataSlice { interfaceSlice[i] = d } ``` ## 11.9.4 通用類型的節點數據結構 在10.1中我們遇到了諸如列表和樹這樣的數據結構,在它們的定義中使用了一種叫節點的遞歸結構體類型,節點包含一個某種類型的數據字段。現在可以使用空接口作為數據字段的類型,這樣我們就能寫出通用的代碼。下面是實現一個二叉樹的部分代碼:通用定義、用于創建空節點的 `NewNode` 方法,及設置數據的 `SetData` 方法. 示例 11.10 node\_structures.go: ``` package main import "fmt" type Node struct { le *Node data interface{} ri *Node } func NewNode(left, right *Node) *Node { return &Node{left, nil, right} } func (n *Node) SetData(data interface{}) { n.data = data } func main() { root := NewNode(nil, nil) root.SetData("root node") // make child (leaf) nodes: a := NewNode(nil, nil) a.SetData("left node") b := NewNode(nil, nil) b.SetData("right node") root.le = a root.ri = b fmt.Printf("%v\n", root) // Output: &{0x125275f0 root node 0x125275e0} } ``` ## 11.9.5 接口到接口 一個接口的值可以賦值給另一個接口變量,只要底層類型實現了必要的方法。這個轉換是在運行時進行檢查的,轉換失敗會導致一個運行時錯誤:這是 'Go' 語言動態的一面,可以那它和 `Ruby` 和 `Python` 這些動態語言相比較。 假定: ``` var ai AbsInterface // declares method Abs() type SqrInterface interface { Sqr() float } var si SqrInterface pp := new(Point) // say *Point implements Abs, Sqr var empty interface{} ``` 那么下面的語句和類型斷言是合法的: ``` empty = pp // everything satisfies empty ai = empty.(AbsInterface) // underlying value pp implements Abs() // (runtime failure otherwise) si = ai.(SqrInterface) // *Point has Sqr() even though AbsInterface doesn’t empty = si // *Point implements empty set // Note: statically checkable so type assertion not necessary. ``` 下面是函數調用的一個例子: ``` type myPrintInterface interface { print() } func f3(x myInterface) { x.(myPrintInterface).print() // type assertion to myPrintInterface } ``` `x` 轉換為 `myPrintInterface` 類型是完全動態的:只要 `x` 的底層類型(動態類型)定義了 `print` 方法這個調用就可以正常運行。
                  <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>

                              哎呀哎呀视频在线观看