mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-12-19 04:04:20 +08:00
rebuild
This commit is contained in:
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="10.7" data-chapter-title="工具" data-filepath="ch10/ch10-07.md" data-basepath=".." data-revision="Wed Dec 16 2015 10:54:29 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="10.7" data-chapter-title="工具" data-filepath="ch10/ch10-07.md" data-basepath=".." data-revision="Mon Dec 21 2015 12:51:02 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -146,7 +146,7 @@
|
||||
|
||||
<b>0.5.</b>
|
||||
|
||||
緻謝
|
||||
致謝
|
||||
</a>
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@
|
||||
|
||||
<b>1.3.</b>
|
||||
|
||||
査找重復的行
|
||||
査找重複的行
|
||||
</a>
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@
|
||||
|
||||
<b>1.4.</b>
|
||||
|
||||
GIF動畫
|
||||
GIF動畵
|
||||
</a>
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@
|
||||
|
||||
<b>1.6.</b>
|
||||
|
||||
併髮穫取多個URL
|
||||
併發穫取多個URL
|
||||
</a>
|
||||
|
||||
|
||||
@@ -479,7 +479,7 @@
|
||||
|
||||
<b>3.3.</b>
|
||||
|
||||
復數
|
||||
複數
|
||||
</a>
|
||||
|
||||
|
||||
@@ -494,7 +494,7 @@
|
||||
|
||||
<b>3.4.</b>
|
||||
|
||||
佈爾型
|
||||
布爾型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -544,7 +544,7 @@
|
||||
|
||||
<b>4.</b>
|
||||
|
||||
復閤數據類型
|
||||
複合數據類型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -857,7 +857,7 @@
|
||||
|
||||
<b>6.2.</b>
|
||||
|
||||
基於指鍼對象的方法
|
||||
基於指針對象的方法
|
||||
</a>
|
||||
|
||||
|
||||
@@ -887,7 +887,7 @@
|
||||
|
||||
<b>6.4.</b>
|
||||
|
||||
方法值和方法錶達式
|
||||
方法值和方法表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -953,7 +953,7 @@
|
||||
|
||||
<b>7.1.</b>
|
||||
|
||||
接口是閤約
|
||||
接口是合約
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1073,7 +1073,7 @@
|
||||
|
||||
<b>7.9.</b>
|
||||
|
||||
示例: 錶達式求值
|
||||
示例: 表達式求值
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1103,7 +1103,7 @@
|
||||
|
||||
<b>7.11.</b>
|
||||
|
||||
基於類型斷言識彆錯誤類型
|
||||
基於類型斷言識别錯誤類型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1214,7 +1214,7 @@
|
||||
|
||||
<b>8.2.</b>
|
||||
|
||||
示例: 併髮的Clock服務
|
||||
示例: 併發的Clock服務
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1229,7 +1229,7 @@
|
||||
|
||||
<b>8.3.</b>
|
||||
|
||||
示例: 併髮的Echo服務
|
||||
示例: 併發的Echo服務
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1274,7 +1274,7 @@
|
||||
|
||||
<b>8.6.</b>
|
||||
|
||||
示例: 併髮的Web爬蟲
|
||||
示例: 併發的Web爬蟲
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1289,7 +1289,7 @@
|
||||
|
||||
<b>8.7.</b>
|
||||
|
||||
基於select的多路復用
|
||||
基於select的多路複用
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1304,7 +1304,7 @@
|
||||
|
||||
<b>8.8.</b>
|
||||
|
||||
示例: 併髮的字典遍歷
|
||||
示例: 併發的字典遍歷
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1319,7 +1319,7 @@
|
||||
|
||||
<b>8.9.</b>
|
||||
|
||||
併髮的退齣
|
||||
併發的退齣
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1354,7 +1354,7 @@
|
||||
|
||||
<b>9.</b>
|
||||
|
||||
基於共享變量的併髮
|
||||
基於共享變量的併發
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1415,7 +1415,7 @@
|
||||
|
||||
<b>9.4.</b>
|
||||
|
||||
內存衕步
|
||||
內存同步
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1460,7 +1460,7 @@
|
||||
|
||||
<b>9.7.</b>
|
||||
|
||||
示例: 併髮的非阻塞緩存
|
||||
示例: 併發的非阻塞緩存
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1475,7 +1475,7 @@
|
||||
|
||||
<b>9.8.</b>
|
||||
|
||||
Goroutines和綫程
|
||||
Goroutines和線程
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1748,7 +1748,7 @@
|
||||
|
||||
<b>12.1.</b>
|
||||
|
||||
為何需要反射?
|
||||
爲何需要反射?
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1793,7 +1793,7 @@
|
||||
|
||||
<b>12.4.</b>
|
||||
|
||||
示例: 編碼S錶達式
|
||||
示例: 編碼S表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1823,7 +1823,7 @@
|
||||
|
||||
<b>12.6.</b>
|
||||
|
||||
示例: 解碼S錶達式
|
||||
示例: 解碼S表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1975,50 +1975,14 @@
|
||||
|
||||
</li>
|
||||
|
||||
<li class="chapter " data-level="14" data-path="exercise/ex.html">
|
||||
|
||||
|
||||
<a href="../exercise/ex.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>14.</b>
|
||||
|
||||
習題解答
|
||||
</a>
|
||||
|
||||
|
||||
<ul class="articles">
|
||||
|
||||
|
||||
<li class="chapter " data-level="14.1" data-path="exercise/ex-ch1.html">
|
||||
|
||||
|
||||
<a href="../exercise/ex-ch1.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>14.1.</b>
|
||||
|
||||
第一章 入門
|
||||
</a>
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="chapter " data-level="15" data-path="errata.html">
|
||||
<li class="chapter " data-level="14" data-path="errata.html">
|
||||
|
||||
|
||||
<a href="../errata.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>15.</b>
|
||||
<b>14.</b>
|
||||
|
||||
勘誤
|
||||
</a>
|
||||
@@ -2061,8 +2025,8 @@
|
||||
|
||||
<h2 id="107-工具">10.7. 工具</h2>
|
||||
<p>本章剩下的部分將討論Go工具箱的特性, 包括如何 下載, 格式化, 構建, 測試 和 安裝 Go 程序.</p>
|
||||
<p>Go的工具箱集閤了一繫列的功能到一個命令集. 它可以看作是一個包管理器(類似於Linux中的apt和rpm工具), 用於包的査詢, 計算的包依賴關繫, 從遠程版本控製繫統和下載它們等任務. 它也是一個構建繫統, 計算文件的依賴關繫, 然後調用編譯器, 滙編器 和 連接器 構建程序, 雖然它故意被設計成沒有標準的make命令那麼復雜. 它也是一個測試驅動程序, 我們在第11章討論測試話題.</p>
|
||||
<p>Go工具箱的命令有着類似"瑞士軍刀"的風格, 帶着一打子的子命令, 有一些我們經常用到, 例如 get, run, build, 和 fmt 等. 你可以運行 <code>go help</code> 命令査看內置的溫度, 為了査詢方便, 我們列齣了最常用的命令:</p>
|
||||
<p>Go的工具箱集合了一繫列的功能到一個命令集. 它可以看作是一個包管理器(類似於Linux中的apt和rpm工具), 用於包的査詢, 計算的包依賴關繫, 從遠程版本控製繫統和下載它們等任務. 它也是一個構建繫統, 計算文件的依賴關繫, 然後調用編譯器, 滙編器 和 連接器 構建程序, 雖然它故意被設計成沒有標準的make命令那麽複雜. 它也是一個測試驅動程序, 我們在第11章討論測試話題.</p>
|
||||
<p>Go工具箱的命令有着類似"瑞士軍刀"的風格, 帶着一打子的子命令, 有一些我們經常用到, 例如 get, run, build, 和 fmt 等. 你可以運行 <code>go help</code> 命令査看內置的溫度, 爲了査詢方便, 我們列齣了最常用的命令:</p>
|
||||
<pre><code>$ go
|
||||
...
|
||||
build compile packages and dependencies
|
||||
@@ -2080,12 +2044,12 @@
|
||||
|
||||
Use "go help [command]" for more information about a command.
|
||||
...
|
||||
</code></pre><p>為了達到零配置的目標, Go的工具箱很多地方都依賴各種約定. 例如, 給定的源文件的名稱, Go工具可以找到對應的包, 因為每個目彔隻包含了單一的包, 併且到的導入路徑和工作區的目彔結構是對應的. 給定一個包的導入路徑, Go工具可以找到對應的目彔中保存對象的文件. 它還可以髮現存儲代碼倉庫的遠程服務器的URL.</p>
|
||||
</code></pre><p>爲了達到零配置的目標, Go的工具箱很多地方都依賴各種約定. 例如, 給定的源文件的名稱, Go工具可以找到對應的包, 因爲每個目録隻包含了單一的包, 併且到的導入路徑和工作區的目録結構是對應的. 給定一個包的導入路徑, Go工具可以找到對應的目録中保存對象的文件. 它還可以發現存儲代碼倉庫的遠程服務器的URL.</p>
|
||||
<h3 id="1071-工作區結構">10.7.1. 工作區結構</h3>
|
||||
<p>對於大多數的Go用戶, 隻需要配置一個名叫GOPATH的環境變量, 用來指定根工作目彔卽可. 當需要切換到不衕工作區的時候, 隻要更新GOPATH就可以了. 例如, 我們在編寫本書時, 將GOPATH設置為 <code>$HOME/gobook</code>:</p>
|
||||
<p>對於大多數的Go用戶, 隻需要配置一個名叫GOPATH的環境變量, 用來指定根工作目録卽可. 當需要切換到不同工作區的時候, 隻要更新GOPATH就可以了. 例如, 我們在編寫本書時, 將GOPATH設置爲 <code>$HOME/gobook</code>:</p>
|
||||
<pre><code>$ export GOPATH=$HOME/gobook
|
||||
$ go get gopl.io/...
|
||||
</code></pre><p>當你用前麫介紹的命令下載本書全部的程序之後, 你的當前工作區的目彔結構是這樣的:</p>
|
||||
</code></pre><p>當你用前面介紹的命令下載本書全部的程序之後, 你的當前工作區的目録結構是這樣的:</p>
|
||||
<pre><code>GOPATH/
|
||||
src/
|
||||
gopl.io/
|
||||
@@ -2108,8 +2072,8 @@ $ go get gopl.io/...
|
||||
pkg/
|
||||
darwin_amd64/
|
||||
...
|
||||
</code></pre><p>GOPATH對應的目彔有三個子目彔. 其中 src 子目彔用於存儲源代碼. 每個包保存在$GOPATH/src的相對路徑為包導入路徑的子目彔中, 例如 gopl.io/ch1/helloworld 相對路徑. 我們看到, 一個GOPATH工作區的src目彔中可能有多個獨立的版本控製, 例如 gopl.io 或 golang.org. 其中 pkg 子目彔用於保存編譯後的包的目標文件, bin 子目彔用於保存編譯後的可執行程序, 例如 helloworld 程序.</p>
|
||||
<p>第二個環境變量 GOROOT 用來指定Go的安裝目彔, 還有它自帶的標準庫包的位置. GOROOT 的目彔結構和 GOPATH 類似, 因此存放 fmt 包的源代碼目彔為 $GOROOT/src/fmt. 用戶一般不需要設置 GOROOT, 默認情況下, Go工具會設置為安裝的位置.</p>
|
||||
</code></pre><p>GOPATH對應的目録有三個子目録. 其中 src 子目録用於存儲源代碼. 每個包保存在$GOPATH/src的相對路徑爲包導入路徑的子目録中, 例如 gopl.io/ch1/helloworld 相對路徑. 我們看到, 一個GOPATH工作區的src目録中可能有多個獨立的版本控製, 例如 gopl.io 或 golang.org. 其中 pkg 子目録用於保存編譯後的包的目標文件, bin 子目録用於保存編譯後的可執行程序, 例如 helloworld 程序.</p>
|
||||
<p>第二個環境變量 GOROOT 用來指定Go的安裝目録, 還有它自帶的標準庫包的位置. GOROOT 的目録結構和 GOPATH 類似, 因此存放 fmt 包的源代碼目録爲 $GOROOT/src/fmt. 用戶一般不需要設置 GOROOT, 默認情況下, Go工具會設置爲安裝的位置.</p>
|
||||
<p>其中 <code>go env</code> 命令用於査看工具涉及的所有環境變量的值, 包括未設置環境變量的默認值. GOOS 用於指定目標操作繫統(例如 android, linux, darwin, 或 windows), GOARCH 用於指定處理器的類型, 例如 amd64, 386, 或 arm. 雖然 GOPATH 是唯一必需要設置的, 但是其它的也有偶爾用到.</p>
|
||||
<pre><code>$ go env
|
||||
GOPATH="/home/gopher/gobook"
|
||||
@@ -2119,31 +2083,31 @@ GOOS="darwin"
|
||||
...
|
||||
</code></pre><h3 id="1072-下載包">10.7.2. 下載包</h3>
|
||||
<p>使用Go工具, 不僅可以根據包導入路徑找到本地工作區的包, 甚至可以從互聯網上找到和更新包.</p>
|
||||
<p>使用命令 <code>go get</code> 可以下載一個單一的包或者用 <code>...</code> 下載整個子目彔裏麫的每個包. Go工具衕時計算併下載所依賴的每個包, 這也是前一個例子中 golang.org/x/net/html 自動齣現在本地工作區目彔的原因.</p>
|
||||
<p>使用命令 <code>go get</code> 可以下載一個單一的包或者用 <code>...</code> 下載整個子目録里面的每個包. Go工具同時計算併下載所依賴的每個包, 這也是前一個例子中 golang.org/x/net/html 自動齣現在本地工作區目録的原因.</p>
|
||||
<p>一旦 <code>go get</code> 命令下載了包, 然後就是安裝包或包對應的命令. 我們將在下一節再關註它的細節, 現在隻是展示下整個過程是如何的簡單. 第一個命令是穫取 golint 工具, 用於檢測Go源代碼的編程風格是否有問題. 第二個命令是用 golint 對 2.6.2節的 gopl.io/ch2/popcount 包代碼進行編碼風格檢査. 它友好地報告了忘記了包的文檔:</p>
|
||||
<pre><code>$ go get github.com/golang/lint/golint
|
||||
$ $GOPATH/bin/golint gopl.io/ch2/popcount
|
||||
src/gopl.io/ch2/popcount/main.go:1:1:
|
||||
package comment should be of the form "Package popcount ..."
|
||||
</code></pre><p><code>go get</code> 命令支持當前流行的託管網站 GitHub, Bitbucket, 和 Launchpad, 可以直接從它們的版本控製繫統請求代碼. 對於其他的網站, 你可能需要指定版本控製繫統的具體路徑和協議, 例如 Git 或 Mercurial. 運行 <code>go help importpath</code> 穫取更新的信息.</p>
|
||||
<p><code>go get</code> 穫取的代碼是眞實的本地存儲倉庫, 不僅僅隻是復製文件, 因此你依然可以使用版本管理工具比較本地代碼的變更, 或者切換到其他的版本. 例如 golang.org/x/net 目彔對應一個 Git 倉庫:</p>
|
||||
<p><code>go get</code> 穫取的代碼是眞實的本地存儲倉庫, 不僅僅隻是複製文件, 因此你依然可以使用版本管理工具比較本地代碼的變更, 或者切換到其他的版本. 例如 golang.org/x/net 目録對應一個 Git 倉庫:</p>
|
||||
<pre><code>$ cd $GOPATH/src/golang.org/x/net
|
||||
$ git remote -v
|
||||
origin https://go.googlesource.com/net (fetch)
|
||||
origin https://go.googlesource.com/net (push)
|
||||
</code></pre><p>需要註意的是導入路徑含有的網站域名和本地Git倉庫遠程的Git服務地址併不相衕, 眞實的Git地址是 go.googlesource.com. 這其實是Go工具箱的一個特性, 可以讓包用一個自定義的導入路徑, 但是眞實的代碼卻是由更通用的服務提供, 例如 googlesource.com 或 github.com. 頁麫 <a href="https://golang.org/x/net/html" target="_blank">https://golang.org/x/net/html</a> 包含了如下的元數據, 告訴 Go 工具Git倉庫的眞實託管地址:</p>
|
||||
</code></pre><p>需要註意的是導入路徑含有的網站域名和本地Git倉庫遠程的Git服務地址併不相同, 眞實的Git地址是 go.googlesource.com. 這其實是Go工具箱的一個特性, 可以讓包用一個自定義的導入路徑, 但是眞實的代碼卻是由更通用的服務提供, 例如 googlesource.com 或 github.com. 頁面 <a href="https://golang.org/x/net/html" target="_blank">https://golang.org/x/net/html</a> 包含了如下的元數據, 告訴 Go 工具Git倉庫的眞實託管地址:</p>
|
||||
<pre><code>$ go build gopl.io/ch1/fetch
|
||||
$ ./fetch https://golang.org/x/net/html | grep go-import
|
||||
<meta name="go-import"
|
||||
content="golang.org/x/net git https://go.googlesource.com/net">
|
||||
</code></pre><p>如果指定 <code>-u</code> 命令行標誌參數, <code>go get</code> 將確保所有的包和依賴的包的版本都是最新的, 然後編譯和安裝它們. 如果不包含該標誌參數, 如果包已經在本地存在, 那麼將不會被更新.</p>
|
||||
<p><code>go get -u</code> 命令隻是簡單地保證每個包是最新版本, 如果你是第一次下載則比較很方便的; 但是如果是髮佈程序則可能是不閤適的, 因為本地程序可能需要對依賴的包做精確的版本依賴管理. 通常的解決方案是使用 vendor 目彔存儲固定版本的代碼, 對本地依賴的包的版本更新也是謹慎和持續可控的. 在 Go 1.5 之前, 一般需要脩改包的導入路徑, 所以復製後 golang.org/x/net/html 導入路徑可能會變為 gopl.io/vendor/golang.org/x/net/html. 最新的Go工具已經支持 vendor 特性, 但限於篇幅這裏併不討論細節. 不過可以通過 <code>go help gopath</code> 目彔査看 Vendor 目彔的幫助.</p>
|
||||
<p><strong>練習 10.3:</strong> 從 <a href="http://gopl.io/ch1/helloworld?go-get=1" target="_blank">http://gopl.io/ch1/helloworld?go-get=1</a> 穫取內容, 査看本書的代碼的眞實託管的網址(<code>go get</code>請求HTML頁麫時包含了 <code>go-get</code> 參數, 以區彆普通的瀏覽器請求.)</p>
|
||||
</code></pre><p>如果指定 <code>-u</code> 命令行標誌參數, <code>go get</code> 將確保所有的包和依賴的包的版本都是最新的, 然後編譯和安裝它們. 如果不包含該標誌參數, 如果包已經在本地存在, 那麽將不會被更新.</p>
|
||||
<p><code>go get -u</code> 命令隻是簡單地保證每個包是最新版本, 如果你是第一次下載則比較很方便的; 但是如果是發布程序則可能是不合適的, 因爲本地程序可能需要對依賴的包做精確的版本依賴管理. 通常的解決方案是使用 vendor 目録存儲固定版本的代碼, 對本地依賴的包的版本更新也是謹慎和持續可控的. 在 Go 1.5 之前, 一般需要脩改包的導入路徑, 所以複製後 golang.org/x/net/html 導入路徑可能會變爲 gopl.io/vendor/golang.org/x/net/html. 最新的Go工具已經支持 vendor 特性, 但限於篇幅這里併不討論細節. 不過可以通過 <code>go help gopath</code> 目録査看 Vendor 目録的幫助.</p>
|
||||
<p><strong>練習 10.3:</strong> 從 <a href="http://gopl.io/ch1/helloworld?go-get=1" target="_blank">http://gopl.io/ch1/helloworld?go-get=1</a> 穫取內容, 査看本書的代碼的眞實託管的網址(<code>go get</code>請求HTML頁面時包含了 <code>go-get</code> 參數, 以區别普通的瀏覽器請求.)</p>
|
||||
<h3 id="1073-構建包">10.7.3. 構建包</h3>
|
||||
<p><code>go build</code> 命令編譯參數指定的每個包. 如果包是一個庫, 則忽略輸齣結果; 這可以用於檢測包的可以正確編譯的.
|
||||
如果包的名字是 main, <code>go build</code> 將調用連接器在當前目彔創建一個可執行程序; 導入路徑的最後一段作為可執行程序的名字.</p>
|
||||
<p>因為每個目彔隻包含一個包, 因此每個可執行程序後者叫Unix朮語中的命令, 會要求放到一個獨立的目彔. 這些目彔有時候會放在名叫 cmd 目彔的子目彔下麫, 例如用於提供Go文檔服務的 golang.org/x/tools/cmd/godoc 命令 (§10.7.4).</p>
|
||||
<p>每個包可以由它們的導入路徑指定, 就像前麫看到的那樣, 或者有一個相對目彔的路徑知道, 必鬚以 <code>.</code> 或 <code>..</code> 開頭. 如果沒有指定參數, 那麼默認指定為當前的目彔. 下麫的命令用於構建衕一個包, 雖然它們的寫法各不相衕:</p>
|
||||
如果包的名字是 main, <code>go build</code> 將調用連接器在當前目録創建一個可執行程序; 導入路徑的最後一段作爲可執行程序的名字.</p>
|
||||
<p>因爲每個目録隻包含一個包, 因此每個可執行程序後者叫Unix術語中的命令, 會要求放到一個獨立的目録. 這些目録有時候會放在名叫 cmd 目録的子目録下面, 例如用於提供Go文檔服務的 golang.org/x/tools/cmd/godoc 命令 (§10.7.4).</p>
|
||||
<p>每個包可以由它們的導入路徑指定, 就像前面看到的那樣, 或者有一個相對目録的路徑知道, 必鬚以 <code>.</code> 或 <code>..</code> 開頭. 如果沒有指定參數, 那麽默認指定爲當前的目録. 下面的命令用於構建同一個包, 雖然它們的寫法各不相同:</p>
|
||||
<pre><code>$ cd $GOPATH/src/gopl.io/ch1/helloworld
|
||||
$ go build
|
||||
</code></pre><p>或者:</p>
|
||||
@@ -2156,7 +2120,7 @@ $ go build ./src/gopl.io/ch1/helloworld
|
||||
<pre><code>$ cd $GOPATH
|
||||
$ go build src/gopl.io/ch1/helloworld
|
||||
Error: cannot find package "src/gopl.io/ch1/helloworld".
|
||||
</code></pre><p>也可以指定包的源文件列錶, 一般這隻用於構建一些小程序或臨時性的實驗. 如果是main包, 將以第一個Go源文件的基礎文件名作為可執行程序的名字.</p>
|
||||
</code></pre><p>也可以指定包的源文件列表, 一般這隻用於構建一些小程序或臨時性的實驗. 如果是main包, 將以第一個Go源文件的基礎文件名作爲可執行程序的名字.</p>
|
||||
<pre><code>$ cat quoteargs.go
|
||||
package main
|
||||
|
||||
@@ -2171,47 +2135,47 @@ func main() {
|
||||
$ go build quoteargs.go
|
||||
$ ./quoteargs one "two three" four\ five
|
||||
["one" "two three" "four five"]
|
||||
</code></pre><p>特彆是對於這類一次性的程序, 我們繫統盡快的構建併運行它. <code>go run</code> 命令結閤了構建和運行的兩個步驟:</p>
|
||||
</code></pre><p>特别是對於這類一次性的程序, 我們繫統盡快的構建併運行它. <code>go run</code> 命令結合了構建和運行的兩個步驟:</p>
|
||||
<pre><code>$ go run quoteargs.go one "two three" four\ five
|
||||
["one" "two three" "four five"]
|
||||
</code></pre><p>第一行的參數列錶中第一個不是以 .go 結尾的將作為可執行程序的參數運行.</p>
|
||||
</code></pre><p>第一行的參數列表中第一個不是以 .go 結尾的將作爲可執行程序的參數運行.</p>
|
||||
<p>默認情況下, <code>go build</code> 命令構建指定的包和它依賴的包, 然後丟棄所有除了最後的可執行文件之外的中間編譯結果. 依賴分析和編譯都是很快的, 但是隨着項目增加到幾十個包和成韆上萬行代碼, 依賴關繫分析和編譯時間的消耗將變的可觀, 可能需要幾秒種, 卽使這些依賴項沒有改變.</p>
|
||||
<p><code>go install</code> 命令和 <code>go build</code> 命令很相似, 但是它保存每個包的編譯成果, 而不是將它們都丟棄. 被編譯的包被保存到 $GOPATH/pkg 目彔下和 src 目彔對應, 可執行程序被保存到 $GOPATH/bin 目彔. (很多用戶將 $GOPATH/bin 添加到可執行程序的蒐索列錶中.) 還有, <code>go install</code> 命令和 <code>go build</code> 命令都不會重新編譯沒有髮生變化的包, 這可以使後續構建更快捷. 為了方便, <code>go build -i</code> 將安裝每個目標所依賴的包.</p>
|
||||
<p>因為編譯對應不衕的操作繫統平颱和CPU架構, <code>go install</code> 會將編譯結果安裝到 GOOS 和 GOARCH 對應的目彔. 例如, 在 Mac 繫統 golang.org/x/net/html 包將被安裝到 $GOPATH/pkg/darwin_amd64 目彔下的 golang.org/x/net/html.a 文件.</p>
|
||||
<p>鍼對不衕操作繫統或CPU的交叉構建也是很簡單的. 隻需要設置好目標對應的GOOS 和 GOARCH, 然後運行構建目彔卽可. 下麫交叉編譯的程序將輸齣它在編譯時操作繫統和CPU類型:</p>
|
||||
<p><code>go install</code> 命令和 <code>go build</code> 命令很相似, 但是它保存每個包的編譯成果, 而不是將它們都丟棄. 被編譯的包被保存到 $GOPATH/pkg 目録下和 src 目録對應, 可執行程序被保存到 $GOPATH/bin 目録. (很多用戶將 $GOPATH/bin 添加到可執行程序的蒐索列表中.) 還有, <code>go install</code> 命令和 <code>go build</code> 命令都不會重新編譯沒有發生變化的包, 這可以使後續構建更快捷. 爲了方便, <code>go build -i</code> 將安裝每個目標所依賴的包.</p>
|
||||
<p>因爲編譯對應不同的操作繫統平颱和CPU架構, <code>go install</code> 會將編譯結果安裝到 GOOS 和 GOARCH 對應的目録. 例如, 在 Mac 繫統 golang.org/x/net/html 包將被安裝到 $GOPATH/pkg/darwin_amd64 目録下的 golang.org/x/net/html.a 文件.</p>
|
||||
<p>針對不同操作繫統或CPU的交叉構建也是很簡單的. 隻需要設置好目標對應的GOOS 和 GOARCH, 然後運行構建目録卽可. 下面交叉編譯的程序將輸齣它在編譯時操作繫統和CPU類型:</p>
|
||||
<pre><code class="lang-Go">gopl.io/ch10/cross
|
||||
|
||||
<span class="hljs-keyword">func</span> main() {
|
||||
fmt.Println(runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
</code></pre>
|
||||
<p>下麫以64位和32位環境分彆執行程序:</p>
|
||||
<p>下面以64位和32位環境分别執行程序:</p>
|
||||
<pre><code>$ go build gopl.io/ch10/cross
|
||||
$ ./cross
|
||||
darwin amd64
|
||||
$ GOARCH=386 go build gopl.io/ch10/cross
|
||||
$ ./cross
|
||||
darwin 386
|
||||
</code></pre><p>有些包可能需要鍼對不衕平颱和處理器類型輸齣不衕版本的代碼, 以便於處理底層的可移植性問題或提供為一些特點代碼提供優化. 如果一個文件名包含了一個操作繫統或處理器類型名字, 例如 net_linux.go 或 asm_amd64.s, Go工具將隻在對應的平颱編譯這些文件. 還有一個特彆的構建註釋註釋可以提供更多的構建控製. 例如, 文件中如果包含下麫的註釋:</p>
|
||||
</code></pre><p>有些包可能需要針對不同平颱和處理器類型輸齣不同版本的代碼, 以便於處理底層的可移植性問題或提供爲一些特點代碼提供優化. 如果一個文件名包含了一個操作繫統或處理器類型名字, 例如 net_linux.go 或 asm_amd64.s, Go工具將隻在對應的平颱編譯這些文件. 還有一個特别的構建註釋註釋可以提供更多的構建控製. 例如, 文件中如果包含下面的註釋:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-comment">// +build linux darwin</span>
|
||||
</code></pre>
|
||||
<p>在包聲明的前麫(含包的註釋), 告訴 <code>go build</code> 隻在鍼對 Linux 或 Mac OS X 是纔編譯這個文件. 下麫的構建註釋錶示不編譯這個文件:</p>
|
||||
<p>在包聲明的前面(含包的註釋), 告訴 <code>go build</code> 隻在針對 Linux 或 Mac OS X 是纔編譯這個文件. 下面的構建註釋表示不編譯這個文件:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-comment">// +build ignore</span>
|
||||
</code></pre>
|
||||
<p>For more details, see the Build Constraints section of the go/build package’s documentation:</p>
|
||||
<p>更多細節, 可以參考 go/build 包的構建約束部分的文檔.</p>
|
||||
<pre><code>$ go doc go/build
|
||||
</code></pre><h3 id="1074-包文檔">10.7.4. 包文檔</h3>
|
||||
<p>Go的編碼風格鼓勵為每個包提供良好的文檔. 包中每個導齣的成員和包聲明前都應該包含添加目的和用法說明的註釋.</p>
|
||||
<p>Go中包文檔註釋一般是完整的句子, 第一行是包的摘要說明, 註釋後僅跟着包聲明語句. 函數的參數或其他的標識符併不需要額外的引號或其他標記註明. 例如, 下麫是 fmt.Fprintf 的文檔註釋.</p>
|
||||
<p>Go的編碼風格鼓勵爲每個包提供良好的文檔. 包中每個導齣的成員和包聲明前都應該包含添加目的和用法説明的註釋.</p>
|
||||
<p>Go中包文檔註釋一般是完整的句子, 第一行是包的摘要説明, 註釋後僅跟着包聲明語句. 函數的參數或其他的標識符併不需要額外的引號或其他標記註明. 例如, 下面是 fmt.Fprintf 的文檔註釋.</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-comment">// Fprintf formats according to a format specifier and writes to w.</span>
|
||||
<span class="hljs-comment">// It returns the number of bytes written and any write error encountered.</span>
|
||||
<span class="hljs-keyword">func</span> Fprintf(w io.Writer, format <span class="hljs-typename">string</span>, a ...<span class="hljs-keyword">interface</span>{}) (<span class="hljs-typename">int</span>, error)
|
||||
</code></pre>
|
||||
<p>Fprintf 函數格式化的細節在 fmt 包文檔中描述. 如果註釋後僅跟着包聲明語句, 那註釋對應整個包的文檔. 包文檔對應的註釋隻能有一個(譯註: 其實可以多個, 它們會組閤成一個包文檔註釋.), 可以齣現在任何一個源文件中. 如果包的註釋內容比較長, 可以當到一個獨立的文件中; fmt 包註釋就有 300 行之多. 這個專門用於保證包文檔的文件通常叫 doc.go.</p>
|
||||
<p>好的文檔併不需要麫麫俱到, 文檔本身應該是簡潔但可不忽略的. 事實上, Go的風格喜歡簡潔的文檔, 併且文檔也是需要想代碼一樣維護的. 對於一組聲明語句, 可以衕一個精鍊的句子描述, 如果是顯而易見的功能則併不需要註釋.</p>
|
||||
<p>在本書中, 隻要空間允許, 我們之前很多包聲明都包含了註釋文檔, 但你可以從標準庫中髮現很多更好的例子. 有兩個工具可以幫到你.</p>
|
||||
<p><code>go doc</code> 命令打印包的聲明和每個成員的文檔註釋, 下麫是整個包的文檔:</p>
|
||||
<p>Fprintf 函數格式化的細節在 fmt 包文檔中描述. 如果註釋後僅跟着包聲明語句, 那註釋對應整個包的文檔. 包文檔對應的註釋隻能有一個(譯註: 其實可以多個, 它們會組合成一個包文檔註釋.), 可以齣現在任何一個源文件中. 如果包的註釋內容比較長, 可以當到一個獨立的文件中; fmt 包註釋就有 300 行之多. 這個專門用於保證包文檔的文件通常叫 doc.go.</p>
|
||||
<p>好的文檔併不需要面面俱到, 文檔本身應該是簡潔但可不忽略的. 事實上, Go的風格喜歡簡潔的文檔, 併且文檔也是需要想代碼一樣維護的. 對於一組聲明語句, 可以同一個精鍊的句子描述, 如果是顯而易見的功能則併不需要註釋.</p>
|
||||
<p>在本書中, 隻要空間允許, 我們之前很多包聲明都包含了註釋文檔, 但你可以從標準庫中發現很多更好的例子. 有兩個工具可以幫到你.</p>
|
||||
<p><code>go doc</code> 命令打印包的聲明和每個成員的文檔註釋, 下面是整個包的文檔:</p>
|
||||
<pre><code>$ go doc time
|
||||
package time // import "time"
|
||||
|
||||
@@ -2236,22 +2200,22 @@ func Since(t Time) Duration
|
||||
func (d Duration) Seconds() float64
|
||||
|
||||
Seconds returns the duration as a floating-point number of seconds.
|
||||
</code></pre><p>該工具併不需要輸入完整的包導入路徑或正確的大小寫. 下麫的命令打印 encoding/json 包的 (*json.Decoder).Decode 方法的文檔:</p>
|
||||
</code></pre><p>該工具併不需要輸入完整的包導入路徑或正確的大小寫. 下面的命令打印 encoding/json 包的 (*json.Decoder).Decode 方法的文檔:</p>
|
||||
<pre><code>$ go doc json.decode
|
||||
func (dec *Decoder) Decode(v interface{}) error
|
||||
|
||||
Decode reads the next JSON-encoded value from its input and stores
|
||||
it in the value pointed to by v.
|
||||
</code></pre><p>第二個工具, 令人睏惑的也是名叫 godoc, 提供可以相互交叉引用的 HTML 頁麫, 但是包含和 <code>go doc</code> 相衕以及更多的信息. 10.1 節演示了 time 包的文檔, 11.6 節將看到godoc演示可以交互的示例程序. godoc 的在綫服務 <a href="https://godoc.org" target="_blank">https://godoc.org</a>, 包含了成韆上萬的開源包的檢索工具.</p>
|
||||
</code></pre><p>第二個工具, 令人睏惑的也是名叫 godoc, 提供可以相互交叉引用的 HTML 頁面, 但是包含和 <code>go doc</code> 相同以及更多的信息. 10.1 節演示了 time 包的文檔, 11.6 節將看到godoc演示可以交互的示例程序. godoc 的在線服務 <a href="https://godoc.org" target="_blank">https://godoc.org</a>, 包含了成韆上萬的開源包的檢索工具.</p>
|
||||
<p>You can also run an instance of godoc in your workspace if you want to browse your own packages. Visit <a href="http://localhost:8000/pkg" target="_blank">http://localhost:8000/pkg</a> in your browser while running this command:</p>
|
||||
<p>你也可以在自己的工作區目彔允許 godoc 服務. 運行下麫的命令, 然後在瀏覽器査看 <a href="http://localhost:8000/pkg" target="_blank">http://localhost:8000/pkg</a> 頁麫:</p>
|
||||
<p>你也可以在自己的工作區目録允許 godoc 服務. 運行下面的命令, 然後在瀏覽器査看 <a href="http://localhost:8000/pkg" target="_blank">http://localhost:8000/pkg</a> 頁面:</p>
|
||||
<pre><code>$ godoc -http :8000
|
||||
</code></pre><p>其中 <code>-analysis=type</code> 和 <code>-analysis=pointer</code> 命令行標誌參數用於打開文檔和代碼中關於靜態分析的結果.</p>
|
||||
<h3 id="1075-內部包">10.7.5. 內部包</h3>
|
||||
<p>在Go程序中, 包的封裝機製是一個重要的特性. 為導齣的標識符隻在衕一個包內部可以訪問, 導齣的標識符則是麫曏全世界可見.</p>
|
||||
<p>有時候, 一個中間的狀態可能也是有用的, 對於一小部分信任的包是可見的, 但併不是對所有調用者都可見. 例如, 當我們計劃將一個大的包拆分為很多小的更容易管理的子包, 但是我們併不想將內部的子包結構也完全暴露齣去. 衕時, 我們肯呢個還希望在內部子包之間共享一些通用的處理包. 或者我們隻是想實驗一個新包的還併不穩定的接口, 暫時隻暴露給一些受限製的客戶端.</p>
|
||||
<p>在Go程序中, 包的封裝機製是一個重要的特性. 爲導齣的標識符隻在同一個包內部可以訪問, 導齣的標識符則是面向全世界可見.</p>
|
||||
<p>有時候, 一個中間的狀態可能也是有用的, 對於一小部分信任的包是可見的, 但併不是對所有調用者都可見. 例如, 當我們計劃將一個大的包拆分爲很多小的更容易管理的子包, 但是我們併不想將內部的子包結構也完全暴露齣去. 同時, 我們肯呢個還希望在內部子包之間共享一些通用的處理包. 或者我們隻是想實驗一個新包的還併不穩定的接口, 暫時隻暴露給一些受限製的客戶端.</p>
|
||||
<p><img src="../images/ch10-01.png" alt=""></p>
|
||||
<p>為了滿足這些需求, Go構建工具支持包含 internal 名字的路徑段的包導入路徑. 這種包叫 internal 包, 一個 internal 包隻能被有和internal目彔有衕一個父目彔的包所導入. 例如, net/http/internal/chunked 內部包隻能被 net/http/httputil 或 net/http 導入, 但是不能被 net/url 包導入. 但是 net/url 包 可以導入 net/http/httputil.</p>
|
||||
<p>爲了滿足這些需求, Go構建工具支持包含 internal 名字的路徑段的包導入路徑. 這種包叫 internal 包, 一個 internal 包隻能被有和internal目録有同一個父目録的包所導入. 例如, net/http/internal/chunked 內部包隻能被 net/http/httputil 或 net/http 導入, 但是不能被 net/url 包導入. 但是 net/url 包 可以導入 net/http/httputil.</p>
|
||||
<pre><code>net/http
|
||||
net/http/internal/chunked
|
||||
net/http/httputil
|
||||
@@ -2260,7 +2224,7 @@ net/url
|
||||
<p><code>go list</code> 工具可以報告可用包的信息. 其最簡單的形式, 可以測試包是否在工作區併打印他的導入路徑:</p>
|
||||
<pre><code>$ go list github.com/go-sql-driver/mysql
|
||||
github.com/go-sql-driver/mysql
|
||||
</code></pre><p><code>go list</code> 參數還可以用 <code>"..."</code> 錶示匹配任意的包的導入路徑. 我們可以用它來列錶工作區中的所有包:</p>
|
||||
</code></pre><p><code>go list</code> 參數還可以用 <code>"..."</code> 表示匹配任意的包的導入路徑. 我們可以用它來列表工作區中的所有包:</p>
|
||||
<pre><code>$ go list ...
|
||||
archive/tar
|
||||
archive/zip
|
||||
@@ -2269,7 +2233,7 @@ bytes
|
||||
cmd/addr2line
|
||||
cmd/api
|
||||
...many more...
|
||||
</code></pre><p>或者是特定子目彔下的所有包:</p>
|
||||
</code></pre><p>或者是特定子目録下的所有包:</p>
|
||||
<pre><code>$ go list gopl.io/ch3/...
|
||||
gopl.io/ch3/basename1
|
||||
gopl.io/ch3/basename2
|
||||
@@ -2282,7 +2246,7 @@ gopl.io/ch3/surface
|
||||
<pre><code>$ go list ...xml...
|
||||
encoding/xml
|
||||
gopl.io/ch7/xmlselect
|
||||
</code></pre><p><code>go list</code> 可以穫取每個包完整的元信息, 而不僅僅隻是導入路徑, 這些信息可以以不衕格式提供給用戶. 其中 <code>-json</code> 標誌參數錶示用JSON格式打印每個包的元信息.</p>
|
||||
</code></pre><p><code>go list</code> 可以穫取每個包完整的元信息, 而不僅僅隻是導入路徑, 這些信息可以以不同格式提供給用戶. 其中 <code>-json</code> 標誌參數表示用JSON格式打印每個包的元信息.</p>
|
||||
<pre><code>$ go list -json hash
|
||||
{
|
||||
"Dir": "/home/gopher/go/src/hash",
|
||||
@@ -2308,23 +2272,23 @@ gopl.io/ch7/xmlselect
|
||||
"unsafe"
|
||||
]
|
||||
}
|
||||
</code></pre><p>參數 <code>-f</code> 允許用戶使用 text/template (§4.6) 的模闆語言定義輸齣文本的格式. 下麫的命令打印 strconv 包的依賴的包, 然後用 join 模闆函數鏈接為一行, 用一個空格分隔:</p>
|
||||
</code></pre><p>參數 <code>-f</code> 允許用戶使用 text/template (§4.6) 的模闆語言定義輸齣文本的格式. 下面的命令打印 strconv 包的依賴的包, 然後用 join 模闆函數鏈接爲一行, 用一個空格分隔:</p>
|
||||
<pre><code>$ go list -f '{{join .Deps " "}}' strconv
|
||||
errors math runtime unicode/utf8 unsafe
|
||||
</code></pre><p>譯註: 上麫的命令在 Windows 的命令行運行會遇到 <code>template: main:1: unclosed action</code> 的錯誤. 產生錯誤的原因是因為命令行對裏麫的 <code>" "</code> 參數進行轉義了. 按照下麫的方法解決轉義字符串的問題:</p>
|
||||
</code></pre><p>譯註: 上面的命令在 Windows 的命令行運行會遇到 <code>template: main:1: unclosed action</code> 的錯誤. 産生錯誤的原因是因爲命令行對里面的 <code>" "</code> 參數進行轉義了. 按照下面的方法解決轉義字符串的問題:</p>
|
||||
<pre><code>$ go list -f "{{join .Deps \" \"}}" strconv
|
||||
</code></pre><p>下麫的命令打印 compress 子目彔下所有包的依賴包列錶:</p>
|
||||
</code></pre><p>下面的命令打印 compress 子目録下所有包的依賴包列表:</p>
|
||||
<pre><code>$ go list -f '{{.ImportPath}} -> {{join .Imports " "}}' compress/...
|
||||
compress/bzip2 -> bufio io sort
|
||||
compress/flate -> bufio fmt io math sort strconv
|
||||
compress/gzip -> bufio compress/flate errors fmt hash hash/crc32 io time
|
||||
compress/lzw -> bufio errors fmt io
|
||||
compress/zlib -> bufio compress/flate errors fmt hash hash/adler32 io
|
||||
</code></pre><p>譯註: Windows 下衕樣有問題, 要避免轉義字符串的問題: </p>
|
||||
</code></pre><p>譯註: Windows 下同樣有問題, 要避免轉義字符串的問題: </p>
|
||||
<pre><code>$ go list -f "{{.ImportPath}} -> {{join .Imports \" \"}}" compress/...
|
||||
</code></pre><p>go list 命令對於一次性的交互式査詢或自動化構建和測試腳本都很有幫助. 我們將在 11.2.4節 中再次使用它. 更多的信息, 包括可設置的字段和意義, 可以用 <code>go help list</code> 命令査看.</p>
|
||||
<p>在本章, 我們解釋了Go工具箱除了測試命令之外的所有重要的命令. 在下一章, 我們將看到如何用 <code>go test</code> 命令去測試Go程序.</p>
|
||||
<p><strong>練習10.4:</strong> 創建一個工具, 根據命令行指定的參數, 報告工作區所有依賴指定包的其他包集閤. 提示: 你需要運行 <code>go list</code> 命令兩次, 一次用於初始化包, 一次用於所有包. 你可能需要用 encoding/json (§4.5) 包來分析輸齣的 JSON 格式的信息.</p>
|
||||
<p><strong>練習10.4:</strong> 創建一個工具, 根據命令行指定的參數, 報告工作區所有依賴指定包的其他包集合. 提示: 你需要運行 <code>go list</code> 命令兩次, 一次用於初始化包, 一次用於所有包. 你可能需要用 encoding/json (§4.5) 包來分析輸齣的 JSON 格式的信息.</p>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user