C語言中文網 目錄

Go語言為任意類型添加方法

Go 語言可以對任何類型添加方法。給一種類型添加方法就像給結構體添加方法一樣,因為結構體也是一種類型。

為基本類型添加方法

在 Go 語言中,使用 type 關鍵字可以定義出新的自定義類型。之后就可以為自定義類型添加各種方法。我們習慣于使用面向過程的方式判斷一個值是否為 0,例如:
if  v == 0 {
    // v等于0
}
如果將 v 當做整型對象,那么判斷 v 值就可以增加一個 IsZero() 方法,通過這個方法就可以判斷 v 值是否為 0,例如:
if  v.IsZero() {
    // v等于0
}
為基本類型添加方法的詳細實現流程如下:
package main

import (
    "fmt"
)

// 將int定義為MyInt類型
type MyInt int

// 為MyInt添加IsZero()方法
func (m MyInt) IsZero() bool {
    return m == 0
}

// 為MyInt添加Add()方法
func (m MyInt) Add(other int) int {
    return other + int(m)
}

func main() {

    var b MyInt

    fmt.Println(b.IsZero())

    b = 1

    fmt.Println(b.Add(2))
}
代碼輸出如下:
true
3

代碼說明如下:
  • 第 8 行,使用 type MyInt int 將 int 定義為自定義的 MyInt 類型。
  • 第 11 行,為 MyInt 類型添加 IsZero() 方法。該方法使用了 (m MyInt) 的非指針接收器。數值類型沒有必要使用指針接收器。
  • 第 16 行,為 MyInt 類型添加 Add() 方法。
  • 第 17 行,由于 m 的類型是 MyInt 類型,但其本身是 int 類型,因此可以將 m 從 MyInt 類型轉換為 int 類型再進行計算。
  • 第 24 行,調用 b 的 IsZero() 方法。由于使用非指針接收器,b的值會被復制進入 IsZero() 方法進行判斷。
  • 第 28 行,調用 b 的 Add() 方法。同樣也是非指針接收器,結果直接通過 Add() 方法返回。

http包中的類型方法

Go 語言提供的 http 包里也大量使用了類型方法。Go 語言使用 http 包進行 HTTP 的請求,使用 http 包的 NewRequest() 方法可以創建一個 HTTP 請求,填充請求中的 http 頭(req.Header),再調用 http.Client 的 Do 包方法,將傳入的 HTTP 請求發送出去。

下面代碼演示創建一個 HTTP 請求,并且設定 HTTP 頭。
package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "strings"
)

func main() {
    client := &http.Client{}

    // 創建一個http請求
    req, err := http.NewRequest("POST", "http://www.163.com/", strings.NewReader("key=value"))

    // 發現錯誤就打印并退出
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
        return
    }

    // 為標頭添加信息
    req.Header.Add("User-Agent", "myClient")

    // 開始請求
    resp, err := client.Do(req)

    // 處理請求的錯誤
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
        return
    }

    data, err := ioutil.ReadAll(resp.Body)
    fmt.Println(string(data))

    defer resp.Body.Close()

}
代碼執行結果如下:

<html>
<head><title>405 Not Allowed</title></head>
<body bgcolor="white">
<center><h1>405 Not Allowed</h1></center>
<hr><center>nginx</center>
</body>
</html>

代碼說明如下:
  • 第 11 行,實例化 HTTP 的客戶端,請求需要通過這個客戶端實例發送。
  • 第 14 行,使用 POST 方式向網易的服務器創建一個 HTTP 請求,第三個參數為 HTTP 的 Body 部分。Body 部分的內容來自字符串,但參數只能接受 io.Reader 類型,因此使用 strings.NewReader() 創建一個字符串的讀取器,返回的 io.Reader 接口作為 http 的 Body 部分供 NewRequest() 函數讀取。創建請求只是構造一個請求對象,不會連接網絡。
  • 第 24 行,為創建好的 HTTP 請求的頭部添加 User-Agent,作用是表明用戶的代理特性。
  • 第 27 行,使用客戶端處理請求,此時 client 將 HTTP 請求發送到網易服務器。服務器響應請求后,將信息返回并保存到 resp 變量中。
  • 第 37 行,讀取響應的 Body 部分并打印。

由于我們構造的請求不是網易服務器所支持的類型,所以服務器返回操作不被運行的 405 號錯誤。

在本例子第 24 行中使用的 req.Header 的類型為 http.Header,就是典型的自定義類型,并且擁有自己的方法。http.Header 的部分定義如下:
type Header map[string][]string

func (h Header) Add(key, value string) {
    textproto.MIMEHeader(h).Add(key, value)
}

func (h Header) Set(key, value string) {
    textproto.MIMEHeader(h).Set(key, value)
}


func (h Header) Get(key string) string {
    return textproto.MIMEHeader(h).Get(key)
}
代碼說明如下:
  • 第 1 行,Header 實際是一個以字符串為鍵、字符串切片為值的映射。
  • 第 3 行,Add() 為 Header 的方法,map 是一個引用類型,因此即便使用 (h Header) 的非指針接收器,也可以修改 map 的值。

為類型添加方法的過程是一個語言層特性,使用類型方法的代碼經過編譯器編譯后的代碼運行效率與傳統的面向過程或面向對象的代碼沒有任何區別。因此,為了代碼便于理解,可以在編碼時使用 Go 語言的類型方法特性。

time包中的類型方法

Go 語言提供的 time 包主要用于時間的獲取和計算等。在這個包中,也使用了類型方法,例如:
package main

import (
    "fmt"
    "time"
)

func main() {
    fmt.Println(time.Second.String())
}
第9行的time.Second是一個常量,下面代碼的加粗部分就是time.Second的定義:
const (
    Nanosecond  Duration = 1
    Microsecond  = 1000 * Nanosecond
    Millisecond  = 1000 * Microsecond
    Second       = 1000 * Millisecond
    Minute       = 60 * Second
    Hour         = 60 * Minute
)
Second 的類型為 Duration,而 Duration 實際是一個 int64 的類型,定義如下:
type Duration int64
它擁有一個 String 的方法,部分定義如下:
func (d Duration) String() string {

    // 一系列生成buf的代碼
    …
   
    return string(buf[w:])
}
Duration.String 可以將 Duration 的值轉為字符串。

精美而實用的網站,提供C語言C++STLLinuxShellJavaGo語言等教程,以及socketGCCviSwing設計模式JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo