<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國際加速解決方案。 廣告
                Go 語言不是一種?*“傳統”*?的面向對象編程語言:它里面沒有類和繼承的概念。 但是 Go 語言里有非常靈活的?**接口**?概念,通過它可以實現很多面向對象的特性。接口提供了一種方式來?**說明**?對象的行為:如果誰能搞定這件事,它就可以用在這兒。 接口定義了一組方法(方法集),但是這些方法不包含(實現)代碼:它們沒有被實現(它們是抽象的)。接口里也不能包含變量。 通過如下格式定義接口: ~~~ type Namer interface { Method1(param_list) return_type Method2(param_list) return_type ... } ~~~ 上面的?`Namer`?是一個?**接口類型**。 (按照約定,只包含一個方法的)接口的名字由方法名加?`[e]r`?后綴組成,例如`Printer`、`Reader`、`Writer`、`Logger`、`Converter`?等等。還有一些不常用的方式(當后綴?`er`?不合適時),比如`Recoverable`,此時接口名以?`able`?結尾,或者以?`I`?開頭(像?`.NET`?或?`Java`?中那樣)。 Go 語言中的接口都很簡短,通常它們會包含 0 個、最多 3 個方法。 不像大多數面向對象編程語言,在 Go 語言中接口可以有值,一個接口類型的變量或一個?**接口值**?:`var ai Namer`,`ai`是一個多字(multiword)數據結構,它的值是?`nil`。它本質上是一個指針,雖然不完全是一回事。指向接口值的指針是非法的,它們不僅一點用也沒有,還會導致代碼錯誤。 [![](https://github.com/Unknwon/the-way-to-go_ZH_CN/raw/master/eBook/images/11.1_fig11.1.jpg?raw=true)](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/images/11.1_fig11.1.jpg?raw=true) 此處的方法指針表是通過運行時反射能力構建的。 類型(比如結構體)實現接口方法集中的方法,每一個方法的實現說明了此方法是如何作用于該類型的:**即實現接口**,同時方法集也構成了該類型的接口。實現了?`Namer`?接口類型的變量可以賦值給?`ai`?(接收者值),此時方法表中的指針會指向被實現的接口方法。當然如果另一個類型(也實現了該接口)的變量被賦值給?`ai`,這二者(譯者注:指針和方法實現)也會隨之改變。 **類型不需要顯式聲明它實現了某個接口:接口被隱式地實現。多個類型可以實現同一個接口**。 **實現某個接口的類型(除了實現接口方法外)可以有其他的方法**。 **一個類型可以實現多個接口**。 **接口類型可以包含一個實例的引用, 該實例的類型實現了此接口(接口是動態類型)**。 即使接口在類型之后才定義,二者處于不同的包中,被單獨編譯:只要類型實現了接口中的方法,它就實現了此接口。 所有這些特性使得接口具有很大的靈活性。 第一個例子: 示例 11.1 interfaces.go: ~~~ package main import "fmt" type Shaper interface { Area() float32 } type Square struct { side float32 } func (sq *Square) Area() float32 { return sq.side * sq.side } func main() { sq1 := new(Square) sq1.side = 5 // var areaIntf Shaper // areaIntf = sq1 // shorter,without separate declaration: // areaIntf := Shaper(sq1) // or even: areaIntf := sq1 fmt.Printf("The square has area: %f\n", areaIntf.Area()) } ~~~ 輸出: ~~~ The square has area: 25.000000 ~~~ 上面的程序定義了一個結構體?`Square`?和一個接口?`Shaper`,接口有一個方法?`Area()`。 在?`main()`?方法中創建了一個?`Square`?的實例。在主程序外邊定義了一個接收者類型是?`Square`?方法的?`Area()`,用來計算正方形的面積:結構體?`Square`?實現了接口?`Shaper`?。 所以可以將一個?`Square`?類型的變量賦值給一個接口類型的變量:`areaIntf = sq1`?。 現在接口變量包含一個指向?`Square`?變量的引用,通過它可以調用?`Square`?上的方法?`Area()`。當然也可以直接在`Square`?的實例上調用此方法,但是在接口實例上調用此方法更令人興奮,它使此方法更具有一般性。接口變量里包含了接收者實例的值和指向對應方法表的指針。 這是?**多態**?的 Go 版本,多態是面向對象編程中一個廣為人知的概念:根據當前的類型選擇正確的方法,或者說:同一種類型在不同的實例上似乎表現出不同的行為。 如果?`Square`?沒有實現?`Area()`?方法,編譯器將會給出清晰的錯誤信息: ~~~ cannot use sq1 (type *Square) as type Shaper in assignment: *Square does not implement Shaper (missing Area method) ~~~ 如果?`Shaper`?有另外一個方法?`Perimeter()`,但是`Square`?沒有實現它,即使沒有人在?`Square`?實例上調用這個方法,編譯器也會給出上面同樣的錯誤。 擴展一下上面的例子,類型?`Rectangle`?也實現了?`Shaper`?接口。接著創建一個?`Shaper`?類型的數組,迭代它的每一個元素并在上面調用?`Area()`?方法,以此來展示多態行為: 示例 11.2 interfaces_poly.go: ~~~ package main import "fmt" type Shaper interface { Area() float32 } type Square struct { side float32 } func (sq *Square) Area() float32 { return sq.side * sq.side } type Rectangle struct { length, width float32 } func (r Rectangle) Area() float32 { return r.length * r.width } func main() { r := Rectangle{5, 3} // Area() of Rectangle needs a value q := &Square{5} // Area() of Square needs a pointer // shapes := []Shaper{Shaper(r), Shaper(q)} // or shorter shapes := []Shaper{r, q} fmt.Println("Looping through shapes for area ...") for n, _ := range shapes { fmt.Println("Shape details: ", shapes[n]) fmt.Println("Area of this shape is: ", shapes[n].Area()) } } ~~~ 輸出: ~~~ Looping through shapes for area ... Shape details: {5 3} Area of this shape is: 15 Shape details: &{5} Area of this shape is: 25 ~~~ 在調用?`shapes[n].Area())`?這個時,只知道?`shapes[n]`?是一個?`Shaper`?對象,最后它搖身一變成為了一個?`Square`?或`Rectangle`?對象,并且表現出了相對應的行為。 也許從現在開始你將看到通過接口如何產生?**更干凈**、**更簡單**?及?**更具有擴展性**?的代碼。在 11.12.3 中將看到在開發中為類型添加新的接口是多么的容易。 下面是一個更具體的例子:有兩個類型?`stockPosition`?和?`car`,它們都有一個?`getValue()`?方法,我們可以定義一個具有此方法的接口?`valuable`。接著定義一個使用?`valuable`?類型作為參數的函數?`showValue()`,所有實現了?`valuable`接口的類型都可以用這個函數。 示例 11.3 valuable.go: ~~~ package main import "fmt" type stockPosition struct { ticker string sharePrice float32 count float32 } /* method to determine the value of a stock position */ func (s stockPosition) getValue() float32 { return s.sharePrice * s.count } type car struct { make string model string price float32 } /* method to determine the value of a car */ func (c car) getValue() float32 { return c.price } /* contract that defines different things that have value */ type valuable interface { getValue() float32 } func showValue(asset valuable) { fmt.Printf("Value of the asset is %f\n", asset.getValue()) } func main() { var o valuable = stockPosition{"GOOG", 577.20, 4} showValue(o) o = car{"BMW", "M3", 66500} showValue(o) } ~~~ 輸出: ~~~ Value of the asset is 2308.800049 Value of the asset is 66500.000000 ~~~ **一個標準庫的例子** `io`?包里有一個接口類型?`Reader`: ~~~ type Reader interface { Read(p []byte) (n int, err error) } ~~~ 定義變量?`r`:`var r io.Reader` 那么就可以寫如下的代碼: ~~~ var r io.Reader r = os.Stdin // see 12.1 r = bufio.NewReader(r) r = new(bytes.Buffer) f,_ := os.Open("test.txt") r = bufio.NewReader(f) ~~~ 上面?`r`?右邊的類型都實現了?`Read()`?方法,并且有相同的方法簽名,`r`?的靜態類型是?`io.Reader`。 **備注** 有的時候,也會以一種稍微不同的方式來使用接口這個詞:從某個類型的角度來看,它的接口指的是:它的所有導出方法,只不過沒有顯式地為這些導出方法額外定一個接口而已。 **練習 11.1**?simple_interface.go: 定義一個接口?`Simpler`,它有一個?`Get()`?方法和一個?`Set()`,`Get()`返回一個整型值,`Set()`?有一個整型參數。創建一個結構體類型?`Simple`?實現這個接口。 接著定一個函數,它有一個?`Simpler`?類型的參數,調用參數的?`Get()`?和?`Set()`?方法。在?`main`?函數里調用這個函數,看看它是否可以正確運行。 **練習 11.2**?interfaces_poly2.go: a) 擴展 interfaces_poly.go 中的例子,添加一個?`Circle`?類型 b) 使用一個抽象類型?`Shape`(沒有字段) 實現同樣的功能,它實現接口?`Shaper`,然后在其他類型里內嵌此類型。擴展 10.6.5 中的例子來說明覆寫。
                  <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>

                              哎呀哎呀视频在线观看