天天看點

Go語言學習筆記 -- 包

包的定義

包是函數和資料的集合,使用pacakge關鍵字開始包的定義。檔案名不需要與包名一緻,包名使用小寫字母。包可以由多個檔案組成,但是每個檔案都要使用相同的

package <name>

這一行,

name

為包的名字。

例如我們在檔案even.go中,使用包名even定義一個包。

package even                    <--開始定義包

func Even(i int) bool {         <--導出的函數
    return i ==
}

func odd(i int) bool {          <--私有函數
    return i ==
}
           

以大寫字母開頭的名字是可以導出的,可以在包的外部通路。小寫字母開頭的名字為私有的,隻能在包内部通路。

現在建構這個包,在$GOPATH下建立一個目錄,将even.go拷貝到目錄下

$ mkdir $GOPATH/src/even
$ cp even.go $GOPATH/src/even/
$ go build
$ go install even
           

建構完成後就可以在myeven.go代碼裡引用這個包:

package main

import (
    "even"    <--導入even包
    "fmt"
)

func main(){
    fmt.Printf("2 is even : %v\n", even.Even());  <--調用even包中的函數
}
           

調用某個包中函數的寫法是

<packagename>.Function()

在 Go 中,當函數的首字母大寫的時候,函數會被從包中導出(在包外部可見,或者說公有的),是以函數名是 Even 。如果修改 myeven.go 的第 10 行,使用未導出的函數even.odd :

fmt.Printf(“Is %d even? %v\n”, i, even.odd(i))

由于使用了 私有 的函數,會得到一個編譯錯誤:

myeven.go:10: cannot refer to unexported name even.odd

概括來說:

• 公有函數的名字以 大寫 字母開頭;

• 私有函數的名字以 小寫 字母開頭。

測試包

在 Go 中為包編寫單元測試應當是一種習慣。編寫測試需要包含 testing 包和程式 go test 。兩者都有良好的文檔。

go test 程式調用了所有的測試函數。even 包沒有定義任何測試函數,執行 go test ,這樣:

$ go test
?         even [no test files]
           

在 測 試 文 件 中 定 義 一 個 測 試 來 修 複 這 個。 測 試 文 件 也 在 包 目 錄 中, 被 命 名 為*_test.go 。 這些測試檔案同 Go 程式中的其他檔案一樣, 但是 go test 隻會執行測試函數。每個測試函數都有相同的辨別,它的名字以 Test 開頭:

func TestXxx(t *testing.T)

編寫測試時,需要告訴 go test 測試是失敗還是成功。測試成功則直接傳回。當測試失敗可以用下面的函數标記 。這是非常重要的(參閱 go doc testing 或 go help testfunc 了解更多):

func (t *T) Fail()

Fail 标記測試函數失敗,但仍然繼續執行。

func (t *T) FailNow()

FailNow 标記測試函數失敗,并且中斷其執行。目前檔案中的其餘的測試将被跳過,然後執行下一個檔案中的測試。

func (t *T) Log(args … i n t e r f a c e { } )

Log 用預設格式對其參數進行格式化,與 Print() 類似,并且記錄文本到錯誤日志。

func (t *T) Fatal(args … i n t e r f a c e { } )

Fatal 等價于 Log() 後跟随 FailNow() 。

将這些湊到一起,就可以編寫測試了。首先,選擇名字 even_test.go 。然後添加下面的内容:

Listing. even 包的測試
package even 
import "testing" 
func TestEven(t *testing.T) { 
    if ! Even) {
        t.Log("2 should be even ! ")
        t.Fail()
    }
}
           

注意在第一行使用了 package even ,測試使用與被測試的包使用相同的名字空間。這不僅僅是為了友善,也允許了測試未導出的函數和結構。然後導入 testing 包,并且在第 5 行定義了這個檔案中唯一的測試函數。展示的 Go 代碼應當沒有任何驚異的地方,檢查了 Even 函數是否工作正常。現在等待了好久的時刻到了,執行測試:

% go test
ok  even s
           

測試執行并且報告 ok 。成功了!

如果重新定義測試函數,就可以看到一個失敗的測試:

// Entering the twilight zone
func TestEven(t *testing.T) {
    if Even() {
        t.Log("2 should be odd ! ")
        t.Fail()
    }
}
           

然後得到:

$ go test even
--- FAIL: TestEven (.s)
    even_test.go:8: 2 should be Even!
FAIL
FAIL    even    0.002s
           

然後你可以以此行事(修複測試的執行個體)

!!!! 在編寫包的時候應當一邊寫代碼,一邊寫(一些)文檔和測試函數。這可以讓你的程式更好,并且它展示了你的努力。

The Go test suite also allows you to incorperate example functions which serve as documentation and as tests. These functions need to start with Example .

func ExampleEven() {
    if Even) {
        fmt.Printf("Is Even\n")
    }
    //Output:
    //Is Even
}
           

Those last two comments lines are part of the example, go test uses those to check the generated output with the text in the comments. If there is a mismatch the test fails.

常用的包

fmt

包 fmt 實作了格式化的 I/O 函數,這與 C 的 printf 和 scanf 類似。格式化短語派生于 C 。一些短語(%-序列)這樣使用:

%v

預設格式的值。當列印結構時,加号(%+v)會增加字段名;

%#v

Go 樣式的值表達;

%T

帶有類型的 Go 樣式的值表達;

io

這個包提供了原始的 I/O 操作界面。它主要的任務是對 os 包這樣的原始的 I/O 進行封裝,增加一些其他相關,使其具有抽象功能用在公共的接口上。

bufio

這個包實作了緩沖的 I/O。它封裝于 io.Reader 和 io.Writer 對象,建立了另一個對象(Reader 和 Writer)在提供緩沖的同時實作了一些文本 I/O 的功能。

sort

sort 包提供了對數組和使用者定義集合的原始的排序功能。

strconv

strconv 包提供了将字元串轉換成基本資料類型,或者從基本資料類型轉換為字元串的功能。

os

os 包提供了與平台無關的作業系統功能接口。其設計是 Unix 形式的。

sync

sync 包提供了基本的同步原語,例如互斥鎖。

flag

flag 包實作了指令行解析。

encoding/json

encoding/json 包實作了編碼與解碼 RFC 4627 [2] 定義的 JSON 對象。

html/template

資料驅動的模闆,用于生成文本輸出,例如 HTML。将模闆關聯到某個資料結構上進行解析。模闆内容指向資料結構的元素(通常結構的字段或者 map 的鍵)控制解析并且決定某個值會被顯示。模闆掃描結構以便解析,而 “遊标” @ 決定了目前位置在結構中的值。

net/http

net/http 實作了 HTTP 請求、響應和 URL 的解析,并且提供了可擴充的 HTTP 服務和基本的 HTTP 用戶端。

unsafe

unsafe 包包含了 Go 程式中資料類型上所有不安全的操作。 通常無須使用這個。

reflect

reflect 包實作了運作時反射,允許程式通過抽象類型操作對象。通常用于處理靜态類型 interface{} 的值,并且通過 Typeof 解析出其動态類型資訊,通常會傳回一個有接口類型 Type 的對象。

os/exec

os/exec 包執行外部指令。