Skip to content

Commit f6ca8ed

Browse files
committedApr 2, 2018
如何编写Go代码
1 parent ccc2ebe commit f6ca8ed

File tree

2 files changed

+359
-3
lines changed

2 files changed

+359
-3
lines changed
 

‎README.md

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# :orange_book: 持续更新中...
22

33
## 第0章 远程安装
4-
4+
55
```golang
66
$ go get github.com/Tinywan/golang-tutorial
7-
```
7+
```
88
## 第1章 介绍和安装
99

1010
### [1 - 介绍和安装](/docs/golang_tutorial_01.md)
@@ -70,7 +70,11 @@ $ go get github.com/Tinywan/golang-tutorial
7070
### 31 - 错误处理
7171
### 32 - 恐慌和恢复
7272

73-
###### 参考
73+
## 官方文档
74+
75+
* [如何编写Go代码](/docs/how_to_write_go_code.md)
76+
77+
###### HELP
7478
* [原文](https://golangbot.com/)
7579
* [译者一](http://blog.csdn.net/u011304970/article/details/74797939)
7680
* [译者二](https://www.studygolang.com/gctt/Noluye)

‎docs/how_to_write_go_code.md

+352
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
如何编写Go代码
2+
========================
3+
4+
简介:介绍如何使用go命令获取、构建和安装包,命令和运行测试。
5+
6+
## 概述
7+
8+
> 目录
9+
10+
* 介绍
11+
* 代码组织
12+
* 概观
13+
* 工作区
14+
* GOPATH环境变量
15+
* 导入路径
16+
* 你的第一个程序
17+
* 你的第一个库
18+
* 包名称
19+
* 测试
20+
* 远程软件包
21+
22+
> 介绍
23+
24+
本文档演示了一个简单Go包的开发过程,并介绍了go工具,这是获取、构建和安装Go包和命令的标准方法。
25+
26+
该go工具要求您以特定方式组织您的代码。
27+
28+
## 代码组织
29+
30+
> 概观
31+
32+
请注意,这与其他编程环境不同,在这些编程环境中,每个项目都有一个单独的工作区,工作区与版本控制存储库紧密相关。
33+
34+
* Go程序员通常将他们所有的Go代码保存在一个工作区中。
35+
* 工作区包含许多版本控制存储库 (例如,由Git管理)。
36+
* 每个存储库都包含一个或多个包。
37+
* 每个软件包由一个目录中的一个或多个Go源文件组成。
38+
* 包的目录的路径决定了它的导入路径。
39+
40+
> 工作区
41+
42+
工作空间是一个目录层次结构,其根目录包含三个目录:
43+
44+
* src 包含Go源文件,
45+
* pkg 包含包对象
46+
* bin 包含可执行命令。
47+
48+
该go工具构建源包并将生成的二进制文件安装到pkg和bin目录。
49+
50+
该`src`子目录通常包含多个版本控制存储库(例如Git或Mercurial),用于跟踪一个或多个源包的开发。
51+
52+
为了让您了解工作空间在实践中的外观,下面是一个例子:
53+
54+
```golang
55+
bin/
56+
hello # 命令可执行文件
57+
outyet # 命令可执行文件
58+
pkg/
59+
linux_amd64/
60+
github.com/golang/example/
61+
stringutil.a # 包对象
62+
src/
63+
github.com/golang/example/
64+
.git/ # Git存储库元数据
65+
hello/
66+
hello.go # 命令源
67+
outyet/
68+
main.go # command source
69+
main_test.go # test source
70+
stringutil/
71+
reverse.go # 包源码
72+
reverse_test.go # 测试源码
73+
golang.org/x/image/
74+
.git/ # Git存储库元数据
75+
bmp/
76+
reader.go # package source
77+
writer.go # package source
78+
... (many more repositories and packages omitted) ...
79+
```
80+
81+
上面的树显示了一个包含两个存储库(example和image)的工作空间。该example库包含两个命令(hello 和outyet)和一个库(`stringutil`)。该image存储库包含该bmp包和其他几个包。
82+
83+
典型的工作空间包含许多包含许多包和命令的源代码库。大多数Go程序员将他们所有的Go源代码和依赖关系保存在一个工作区中。
84+
85+
命令和库由不同类型的源代码包构建而成。
86+
87+
> 第一个程序
88+
89+
要编译并运行一个简单的程序,首先选择一个包路径(我们将使用 `github.com/user/hello`)并在工作区内创建一个相应的包目录:
90+
91+
```bash
92+
mkdir $GOPATH/src/github.com/user/hello
93+
```
94+
95+
接下来,创建一个名为hello.go该目录内的文件,其中包含以下Go代码。
96+
97+
```golang
98+
package main
99+
100+
import "fmt"
101+
102+
func main() {
103+
fmt.Printf("Hello, world.\n")
104+
}
105+
```
106+
107+
现在,您可以使用该go工具构建和安装该程序
108+
109+
```golang
110+
$ go install github.com/user/hello // 编译包文件并且编译整个程序
111+
```
112+
113+
请注意,您可以从系统上的任何位置运行此命令。该 go工具通过查找 `github.com/user/hello ` 指定的工作区内的程序包来查找源代码 `GOPATH`。
114+
115+
如果`go install`从软件包目录运行,也可以省略软件包路径:
116+
117+
```golang
118+
$ cd $GOPATH/src/github.com/user/hello
119+
$ go install
120+
```
121+
122+
该命令构建`hello`命令,生成可执行的二进制文件。然后它将该二进制文件安装到工作空间的`bin`目录`hello`(或者在Windows下`hello.exe`)。在我们的例子中,那将是`$GOPATH/bin/hello`,这是`$HOME/go/bin/hello`。
123+
124+
该`go`工具只会在发生错误时打印输出,因此如果这些命令不产生任何输出,它们将成功执行。
125+
126+
您现在可以通过在命令行键入完整路径来运行该程序:
127+
128+
```bash
129+
$ $GOPATH/bin/hello
130+
Hello, world.
131+
```
132+
或者,如您添加`$GOPATH/bin`到您的`PATH`,只需键入二进制名称:
133+
134+
```golang
135+
$ hello
136+
Hello, world.
137+
```
138+
139+
如果您正在使用源代码管理系统,现在应该是初始化存储库,添加文件并提交第一个更改的好时机。再一次,这一步是可选的:你不需要使用源代码控制来编写Go代码。
140+
141+
```bash
142+
$ cd $GOPATH/src/github.com/user/hello
143+
$ git init
144+
Initialized empty Git repository in /home/user/work/src/github.com/user/hello/.git/
145+
$ git add hello.go
146+
$ git commit -m "initial commit"
147+
[master (root-commit) 0b4507d] initial commit
148+
1 file changed, 1 insertion(+)
149+
create mode 100644 hello.go
150+
$ git remote add origin https://github.com/Tinywan/hello.git
151+
$ git push -u origin master
152+
```
153+
将代码推送到远程存储库作为自己的练习。
154+
155+
> 你的第一库
156+
157+
我们来编写一个库并从`hello`程序中使用它。
158+
159+
再次,第一步是选择一个包路径(我们将使用 `github.com/user/stringutil`)并创建包目录:
160+
161+
```bash
162+
$ mkdir $GOPATH/src/github.com/user/stringutil
163+
```
164+
165+
接下来,使用以下内容创建一个名称在该目录中的文件。
166+
167+
```golang
168+
// Package stringutil contains utility functions for working with strings.
169+
package stringutil
170+
171+
// Reverse returns its argument string reversed rune-wise left to right.
172+
func Reverse(s string) string {
173+
r := []rune(s)
174+
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
175+
r[i], r[j] = r[j], r[i]
176+
}
177+
return string(r)
178+
}
179+
```
180+
181+
现在,测试该软件包是用下面用`go build`命令进行代码编译:
182+
183+
```bash
184+
$ go build github.com/user/stringutil // 测试编译,检查编译是否有编译错误
185+
```
186+
187+
或者,如果您在包的源目录中工作,只需:
188+
189+
```bash
190+
$ go build
191+
```
192+
193+
这不会产生输出文件。为此,必须使用`go install`将包对象放置在工作空间的`pkg`目录中的方法。
194+
195+
确认stringutil软件包构建完成后,修改原始文件`hello.go`(位于 `$GOPATH/src/github.com/user/hello`)以使用它:
196+
197+
```golang
198+
package main
199+
200+
import (
201+
"fmt"
202+
"github.com/user/stringutil"
203+
)
204+
205+
func main() {
206+
fmt.Printf(stringutil.Reverse("!oG ,olleH"))
207+
}
208+
```
209+
210+
无论何时该go工具**安装包或二进制文件**,**它也会安装它所具有的任何依赖关系**。所以当你安装hello程序
211+
212+
```bash
213+
$ go install github.com/user/hello
214+
```
215+
216+
该`stringutil`包也将自动安装。
217+
218+
运行该程序的新版本,您应该看到一条新的反转消息:
219+
220+
```bash
221+
$ hello
222+
Hello, Go!
223+
```
224+
225+
完成上述步骤后,您的工作空间应如下所示:
226+
227+
```bash
228+
bin/
229+
hello # command executable
230+
pkg/
231+
linux_amd64/ # this will reflect your OS and architecture
232+
github.com/user/
233+
stringutil.a # package object
234+
src/
235+
github.com/user/
236+
hello/
237+
hello.go # command source
238+
stringutil/
239+
reverse.go # package source
240+
```
241+
242+
请注意,`go install`将`stringutil.a`对象放置在`pkg/linux_amd64`镜像源目录中的目录中。这样未来的`go`工具调用可以找到包对象并避免不必要地重新编译包。该`linux_amd64`部分有助于交叉编译,并将反映您的系统的操作系统和体系结构。
243+
244+
**Go命令可执行文件是静态链接的**,包对象不需要存在来运行Go程序。
245+
246+
> 包名称
247+
248+
Go源文件中的第一条语句必须是
249+
250+
```bash
251+
package name
252+
```
253+
254+
这里`name`是对进口的包的默认名称。(包中的所有文件都必须使用相同的文件`name`)
255+
256+
Go的惯例是包名称是导入路径的最后一个元素:`crypto/rot13`应该命名导入为“ ” 的包rot13。
257+
258+
可执行命令必须始终使用`package main`。
259+
260+
没有要求软件包名称在链接到一个二进制文件的所有软件包中唯一,**只需要导入路径(它们的完整文件名)是唯一的**。
261+
262+
请参阅[Effective Go](http://127.0.0.1:8080/doc/effective_go.html#names)详细了解Go的命名约定。
263+
264+
> 测试
265+
266+
Go有一个由`go test `命令和`testing`包组成的轻量级测试框架。
267+
268+
您通过创建一个名称以文件名结尾的文件来编写一个测试`_test.go` ,其中包含以TestXXX签名 命名的函数`func (t *testing.T)`。测试框架运行每个这样的功能; 如果函数调用失败函数(如t.Error或)` t.Fail`,则认为测试失败。
269+
270+
`stringutil`通过创建`$GOPATH/src/github.com/user/stringutil/reverse_test.go`包含以下Go代码的文件 向测试包 添加测试。
271+
272+
```golang
273+
package stringutil
274+
275+
import "testing"
276+
277+
func TestReverse(t *testing.T) {
278+
cases := []struct {
279+
in, want string
280+
}{
281+
{"Hello, world", "dlrow ,olleH"},
282+
{"Hello, 世界", "界世 ,olleH"},
283+
{"", ""},
284+
}
285+
for _, c := range cases {
286+
got := Reverse(c.in)
287+
if got != c.want {
288+
t.Errorf("Reverse(%q) == %q, want %q", c.in, got, c.want)
289+
}
290+
}
291+
}
292+
```
293+
294+
然后运行测试`go test`:
295+
296+
```bash
297+
$ go test github.com/user/stringutil
298+
ok github.com/user/stringutil 0.165s
299+
```
300+
301+
与往常一样,如果您正在go从软件包目录运行该工具,则可以省略软件包路径:
302+
303+
```bash
304+
$ go test
305+
ok github.com/user/stringutil 0.165s
306+
```
307+
运行`go help test`并查看 测试包文档以获取更多详细信息。
308+
309+
> 远程软件包
310+
311+
导入路径可以描述如何使用Git或Mercurial等版本控制系统获取软件包源代码。该go工具使用此属性从远程存储库自动获取软件包。例如,本文档中描述的示例也保存在GitHub托管的Git存储库中` github.com/golang/example`。如果您在存储库的导入路径中包含存储库URL,` go get`将自动获取,构建和安装它:
312+
313+
```bash
314+
$ go get github.com/golang/example/hello
315+
$ $GOPATH/bin/hello
316+
Hello, Go examples!
317+
```
318+
319+
如果指定的软件包不在工作区中,`go get `则将其放入由指定的第一个工作区内`GOPATH`。(如果包已经存在,则`go get`跳过远程抓取并且行为与`go install`相同)
320+
321+
发出上述`go get`命令后,工作空间目录树现在应该如下所示:
322+
323+
```golang
324+
bin/
325+
hello # command executable
326+
pkg/
327+
linux_amd64/
328+
github.com/golang/example/
329+
stringutil.a # package object
330+
github.com/user/
331+
stringutil.a # package object
332+
src/
333+
github.com/golang/example/
334+
.git/ # Git repository metadata
335+
hello/
336+
hello.go # command source
337+
stringutil/
338+
reverse.go # package source
339+
reverse_test.go # test source
340+
github.com/user/
341+
hello/
342+
hello.go # command source
343+
stringutil/
344+
reverse.go # package source
345+
reverse_test.go # test source
346+
```
347+
348+
hello在GitHub上托管的命令取决于`stringutil`同一个存储库中的软件包。在导入`hello.go`文件中使用相同的导入路径约定,所以` go get`命令能够找到并安装相关的包了。
349+
350+
导入`“github.com/golang/example/stringutil”`这个约定是让你的Go软件包可供其他人使用的最简单的方法。在转到维基 和`godoc.org` 提供外部围棋项目清单。
351+
352+
有关在go工具中使用远程存储库的更多信息,请参阅 [go help importpath](http://127.0.0.1:8080/cmd/go/#hdr-Remote_import_paths)。

0 commit comments

Comments
 (0)
Please sign in to comment.