gopl-zh.github.com/ch2/ch2-06.md

3.9 KiB
Raw Blame History

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
// 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°CKelvin絶對溫度1K和攝氏度1°C的單位間隔是一樣的。

{% include "./ch2-06-1.md" %}

{% include "./ch2-06-2.md" %}