9.筆記go語言——方法和介面

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

9.筆記go語言——方法和介面

方法

Go 沒有類。然而,仍然可以在結構體類型上定義方法。

方法接收者 出現在 func 關鍵字和方法名之間的參數中。

package main

import (

           "fmt"

           "math"

)

type Vertex struct {

           X, Yfloat64

}

func (v *Vertex) Abs() float64 {

           returnmath.Sqrt(v.X*v.X + v.Y*v.Y)

}

func main() {

           v :=&Vertex{3, 4}

           fmt.Println(v.Abs())

}

執行:

           5

你可以對包中的 任意 類型定義任意方法,而不僅僅是針對結構體。

但是,不能對來自其他包的類型或基礎類型定義方法。

package main

import (

           "fmt"

           "math"

)

type MyFloat float64

func (f MyFloat) Abs() float64 {

           if f< 0 {

                     returnfloat64(-f)

           }

           returnfloat64(f)

}

func main() {

           f :=MyFloat(-math.Sqrt2)

           fmt.Println(f.Abs())

}

執行結果:

1.4142135623730951

接收者為指標的方法

方法可以與命名類型或命名類型的指標關聯。

剛剛看到的兩個 Abs 方法。一個是在 *Vertex 指標類型上,而另一個在 MyFloat 實值型別上。有兩個原因需要使用指標接收者。首先避免在每個方法調用中拷貝值(如果實值型別是大的結構體的話會更有效率)。其次,方法可以修改接收者指向的值。

嘗試修改 Abs 的定義,同時 Scale 方法使用 Vertex 代替 *Vertex 作為接收者。

當 v 是 Vertex 的時候 Scale 方法沒有任何作用。`Scale` 修改 `v`。當 v 是一個值(非指標),方法看到的是 Vertex 的副本,並且無法修改原始值。

Abs 的工作方式是一樣的。只不過,僅僅讀取`v`。所以讀取的是原始值(通過指標)還是那個值的副本並沒有關係。

package main

import (

           "fmt"

           "math"

)

type Vertex struct {

           X, Yfloat64

}

func (v *Vertex) Scale(f float64) {

           v.X =v.X * f

           v.Y =v.Y * f

}

func (v *Vertex) Abs() float64 {

           returnmath.Sqrt(v.X*v.X + v.Y*v.Y)

}

func main() {

           v :=&Vertex{3, 4}

           v.Scale(5)

           fmt.Println(v,v.Abs())

}

執行:

           &{1520} 25

介面

介面類型是由一組方法定義的集合。

介面類型的值可以存放實現這些方法的任何值。

注意: 列子代碼的 22 行存在一個錯誤。由於 Abs 只定義在 *Vertex(指標類型) 上,所以 Vertex(實值型別) 不滿足 `Abser`。

package main

import (

           "fmt"

           "math"

)

type Abser interface {

           Abs()float64

}

func main() {

           var aAbser

           f :=MyFloat(-math.Sqrt2)

           v :=Vertex{3, 4}

 

           a =f  // a MyFloat 實現了 Abser

           a =&v // a *Vertex 實現了Abser

 

           // 下面一行,v是一個 Vertex(而不是 *Vertex)

           // 所以沒有實現 Abser。

           a = v

 

           fmt.Println(a.Abs())

}

type MyFloat float64

func (f MyFloat) Abs() float64 {

           if f< 0 {

                     returnfloat64(-f)

           }

           returnfloat64(f)

}

type Vertex struct {

           X, Yfloat64

}

func (v *Vertex) Abs() float64 {

           returnmath.Sqrt(v.X*v.X + v.Y*v.Y)

}

           #command-line-arguments

           .\hello.go:22:cannot use v (type Vertex) as type Abser in assignment:

                     Vertexdoes not implement Abser (Abs method has pointer receiver)

           exitstatus 2

隱式介面

類型通過實現那些方法來實現介面。沒有顯式聲明的必要;所以也就沒有關鍵字“implements“。

隱式介面解藕了實現介面的包和定義介面的包:互不依賴。

因此,也就無需在每一個實現上增加新的介面名稱,這樣同時也鼓勵了明確的介面定義。

包 io 定義了 Reader 和 `Writer`;其實不一定要這麼做。

package main

import (

           "fmt"

           "os"

)

type Reader interface {

           Read(b[]byte) (n int, err error)

}

type Writer interface {

           Write(b[]byte) (n int, err error)

}

type ReadWriter interface {

           Reader

           Writer

}

func main() {

           var wWriter

           //os.Stdout 實現了Writer

           w =os.Stdout

           fmt.Fprintf(w,"hello, writer\n")

}

執行:

           hello,writer

Stringers

一個普遍存在的介面是 fmt 包中定義的 Stringer。

type Stringer struct {

    String() string

}

Stringer 是一個可以用字串描述自己的類型。`fmt`包(還有許多其他包)使用這個來進行輸出。

package main

import "fmt"

type Person struct {

           Namestring

           Age  int

}

func (p Person) String() string {

           returnfmt.Sprintf("%v (%v years)", p.Name, p.Age)

}

func main() {

           a := Person{"ArthurDent", 42}

           z :=Person{"Zaphod Beeblebrox", 9001}

           fmt.Println(a,z)

}

執行:

           ArthurDent (42 years) Zaphod Beeblebrox (9001 years)

錯誤

Go 程式使用 error 值來表示錯誤狀態。

與 fmt.Stringer 類似,`error` 類型是一個內建介面:

type error interface {

   Error() string

}

(與 fmt.Stringer 類似,`fmt` 包在輸出時也會試圖匹配`error`。)

通常函數會返回一個 error 值,調用的它的代碼應當判斷這個錯誤是否等於 `nil`,來進行錯誤處理。

i, err := strconv.Atoi("42")

if err != nil {

   fmt.Printf("couldn't convert number: %v\n", err)

}

fmt.Println("Converted integer:",i)

error 為 nil 時表示成功;非 nil 的 error 表示錯誤。

package main

import (

           "fmt"

           "time"

)

type MyError struct {

           Whentime.Time

           Whatstring

}

func (e *MyError) Error() string {

           returnfmt.Sprintf("at %v, %s",

                     e.When,e.What)

}

func run() error {

           return&MyError{

                     time.Now(),

                     "itdidn't work",

           }

}

func main() {

           iferr := run(); err != nil {

                     fmt.Println(err)

           }

}

執行:

           at2016-06-16 23:10:58.7118248 +0800 CST, it didn't work

 

Readers

io 包指定了 io.Reader 介面, 它表示從資料流結尾讀取。

Go 標準庫包含了這個介面的許多實現, 包括檔案、網路連接、壓縮、加密等等。

io.Reader 介面有一個 Read 方法:

func (T) Read(b []byte) (n int, err error)

Read 用資料填充指定的位元組 slice,並且返回填充的位元組數和錯誤資訊。 在遇到資料流結尾時,返回 io.EOF 錯誤。

例子代碼建立了一個 strings.Reader。 並且以每次 8 位元組的速度讀取它的輸出。

package main

import (

           "fmt"

           "io"

           "strings"

)

func main() {

           r :=strings.NewReader("Hello, Reader!")

           b :=make([]byte, 8)

           for {

                     n,err := r.Read(b)

                     fmt.Printf("n= %v err = %v b = %v\n", n, err, b)

                     fmt.Printf("b[:n]= %q\n", b[:n])

                     iferr == io.EOF {

                                break

                     }

           }

}

執行:

           n= 8 err = <nil> b = [72 101 108 108 111 44 32 82]

           b[:n]= "Hello, R"

           n= 6 err = <nil> b = [101 97 100 101 114 33 32 82]

           b[:n]= "eader!"

           n= 0 err = EOF b = [101 97 100 101 114 33 32 82]

           b[:n]= ""


Web 服務器

包 http 通過任何實現了 http.Handler 的值來響應 HTTP 要求:

package http

 

type Handler interface {

   ServeHTTP(w ResponseWriter, r *Request)

}

在這個例子中,類型 Hello 實現了 `http.Handler`。

訪問 http://localhost:4000/ 會看到來自程式的問候。

package main

import (

           "fmt"

           "log"

           "net/http"

)

type Hello struct{}

func (h Hello) ServeHTTP(

           whttp.ResponseWriter,

           r*http.Request) {

           fmt.Fprint(w,"Hello!")

}

func main() {

           var hHello

           err:= http.ListenAndServe("localhost:4000", h)

           iferr != nil {

                     log.Fatal(err)

           }

}

圖片

Packageimage 定義了 Image 介面:

package image

 

type Image interface {

   ColorModel() color.Model

   Bounds() Rectangle

   At(x, y int) color.Color

}

*注意*:`Bounds` 方法的 Rectangle 傳回值實際上是一個 image.Rectangle, 其定義在 image 包中。

(參閱文檔瞭解全部資訊。)

color.Color 和 color.Model 也是介面,但是通常因為直接使用預定義的實現 image.RGBA 和 image.RGBAModel 而被忽視了。這些介面和類型由image/color包定義。

package main

 

import (

           "fmt"

           "image"

)

 

func main() {

           m :=image.NewRGBA(image.Rect(0, 0, 100, 100))

           fmt.Println(m.Bounds())

           fmt.Println(m.At(0,0).RGBA())

}

執行:

           (0,0)-(100,100)

           00 0 0

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.