2.6. 包和文件

Go語言中的包和其他語言的庫或模塊的概念類似,目的都是爲了支持模塊化、封裝、單獨編譯和代碼重用。一個包的源代碼保存在一個或多個以.go爲文件後綴名的源文件中,通常一個包所在目録路徑的後綴是包的導入路徑;例如包gopl.io/ch1/helloworld對應的目録路徑是$GOPATH/src/gopl.io/ch1/helloworld。

每個包都對應一個獨立的名字空間。例如,在image包中的Decode函數和在unicode/utf16包中的 Decode函數是不同的。要在外部引用該函數,必須顯式使用image.Decode或utf16.Decode形式訪問。

包還可以讓我們通過控製哪些名字是外部可見的來隱藏內部實現信息。在Go語言中,一個簡單的規則是:如果一個名字是大寫字母開頭的,那麽該名字是導出的(譯註:因爲漢字不區分大小寫,因此漢字開頭的名字是沒有導出的)。

爲了演示包基本的用法,先假設我們的溫度轉換軟件已經很流行,我們希望到Go語言社區也能使用這個包。我們該如何做呢?

讓我們創建一個名爲gopl.io/ch2/tempconv的包,這是前面例子的一個改進版本。(我們約定我們的例子都是以章節順序來編號的,這樣的路徑更容易閲讀)包代碼存儲在兩個源文件中,用來演示如何在一個源文件聲明然後在其他的源文件訪問;雖然在現實中,這樣小的包一般隻需要一個文件。

我們把變量的聲明、對應的常量,還有方法都放到tempconv.go源文件中:

gopl.io/ch2/tempconv ```Go // Package tempconv performs Celsius and Fahrenheit conversions. package tempconv

import “fmt”

type Celsius float64 type Fahrenheit float64

const ( AbsoluteZeroC Celsius = -273.15 FreezingC Celsius = 0 BoilingC Celsius = 100 )

func (c Celsius) String() string { return fmt.Sprintf(“%g°C”, c) } func (f Fahrenheit) String() string { return fmt.Sprintf(“%g°F”, f) } ```

轉換函數則放在另一個conv.go源文件中:

package tempconv

// CToF converts a Celsius temperature to Fahrenheit.
func CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9/5 + 32) }

// FToC converts a Fahrenheit temperature to Celsius.
func FToC(f Fahrenheit) Celsius { return Celsius((f - 32) * 5 / 9) }

每個源文件都是以包的聲明語句開始,用來指名包的名字。當包被導入的時候,包內的成員將通過類似tempconv.CToF的形式訪問。而包級别的名字,例如在一個文件聲明的類型和常量,在同一個包的其他源文件也是可以直接訪問的,就好像所有代碼都在一個文件一樣。要註意的是tempconv.go源文件導入了fmt包,但是conv.go源文件併沒有,因爲這個源文件中的代碼併沒有用到fmt包。

因爲包級别的常量名都是以大寫字母開頭,它們可以像tempconv.AbsoluteZeroC這樣被外部代碼訪問:

fmt.Printf("Brrrr! %v\n", tempconv.AbsoluteZeroC) // "Brrrr! -273.15°C"

要將攝氏溫度轉換爲華氏溫度,需要先用import語句導入gopl.io/ch2/tempconv包,然後就可以使用下面的代碼進行轉換了:

fmt.Println(tempconv.CToF(tempconv.BoilingC)) // "212°F"

在每個源文件的包聲明前僅跟着的註釋是包註釋(§10.7.4)。通常,包註釋的第一句應該先是包的功能概要説明。一個包通常隻有一個源文件有包註釋(譯註:如果有多個包註釋,目前的文檔工具會根據源文件名的先後順序將它們鏈接爲一個包註釋)。如果包註釋很大,通常會放到一個獨立的doc.go文件中。

練習 2.1: 向tempconv包添加類型、常量和函數用來處理Kelvin絶對溫度的轉換,Kelvin 絶對零度是−273.15°C,Kelvin絶對溫度1K和攝氏度1°C的單位間隔是一樣的。

{% include “./ch2-06-1.md” %}

{% include “./ch2-06-2.md” %}