Golang Getting-started.md

一、hello world和一个示例

  1. 首先创建一个目录,并构建初始化模块
1
2
3
4
5
6
cd
mkdir hello
cd hello

## 启用依赖项跟踪
go mod init example/hello

hello.go代码

1
2
3
4
5
6
7
8
9
10
package main

import "fmt"

import "rsc.io/quote"

func main() {
fmt.Println("hello, World!")
fmt.Println(quote.Go())
}
  1. 下载依赖模块
1
go mod tidy
  1. 执行代码
1
go run .

二、自定义模块

  1. 新建一个greetings目录,并初始化模块
1
2
3
4
5
cd
mkdir greetings
cd greetings

go mod init example.com/greetings
  1. 新建greetings.go文件,代码如下
1
2
3
4
5
6
7
8
9
package greetings

import "fmt"

// 为指定的人返回问候语
func Hello(name string) string {
message := fmt.Sprintf("Hi, %v. Welcome!", name)
return message
}

三、引入自定义模块

  1. 新建一个hello模块,并初始化(同第一步)
1
2
3
4
5
cd
mkdir hello
cd hello

go mod init example.com/hello
  1. 编辑hello.go代码,引入example.com/greetings模块
1
2
3
4
5
6
7
8
9
10
11
package main

import (
"fmt"
"example.com/greetings"
)

func main() {
message := greetings.Hello("Zerchin")
fmt.Println(message)
}
  1. 正常example.com是一个可访问的地址,这里由于是我们自定义的模块,所以需要替换成本地路径,如下
1
go mod edit -replace example.com/greetings=../greetings

查看go.mod文件可以看到多了一行replace xxxx

  1. 添加自定义模块
1
go mod tidy

查看go.mod文件可以看到多了一行require xxx

  1. 执行代码
1
go run .

输出

1
Hi, Zerchin. Welcome!

四、返回错误并处理

  1. 编辑greetings/greetings.go文件,加入错误处理代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package greetings

import (
"fmt"
"errors"
)

// Hello为指定的人返回问候语
func Hello(name string) (string, error) {
// 如果没有传递name,则返回错误
if name == "" {
return "", errors.New("empty name")
}
message := fmt.Sprintf("Hi, %v. Welcome!", name)
return message, nil
}
  1. 编辑hello/hello.go文件,加入错误日志输出代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
"fmt"
"log"
"example.com/greetings"
)

func main() {
// 设置日志的属性
log.SetPrefix("greetings: ")
log.SetFlags(0)

message, err := greetings.Hello("")

// 错误处理
if err != nil {
log.Fatal(err)
}

输出如下:

1
2
3
$ go run .
greetings: empty name
exit status 1

五、随机返回问候语

  1. 编辑greetings/greetings.go文件,加入随机返回问候语的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package greetings

import (
"fmt"
"errors"
"math/rand"
"time"
)

// Hello为指定的人返回问候语
func Hello(name string) (string, error) {
// 如果没有传递name,则返回错误
if name == "" {
return "", errors.New("empty name")
}
//使用随机的一组问候语
message := fmt.Sprintf(randomFormat(), name)
return message, nil
}

// 设置初始值,没有这个就没有随机数
func init() {
rand.Seed(time.Now().UnixNano())
}

//随机返回一组问候语
func randomFormat() string {
formats := []string{
"Hi, %v. Welcome!",
"Great to see youm %v",
"Hail, %v! Well met!",
}

return formats[rand.Intn(len(formats))]
}
  1. 编辑hello/hello.go文件,调用随机问候语
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
"fmt"
"log"
"example.com/greetings"
)


func main() {
// 设置日志的属性
log.SetPrefix("greetings: ")
log.SetFlags(0)

message, err := greetings.Hello("Zerchin")

// 错误处理
if err != nil {
log.Fatal(err)
}

fmt.Println(message)
}
  1. 执行代码
1
2
3
4
5
6
$ go run .
Hail, Zerchin! Well met!
$ go run .
Great to see youm Zerchin
$ go run .
Hi, Zerchin. Welcome!

六、回复多人问候

这里新增一个函数去调用原有的函数

  1. 编辑greetings/greetings.go文件,新增一个Hellos函数,并去调用Hello函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package greetings

import (
"fmt"
"errors"
"math/rand"
"time"
)

// Hello为指定的人返回问候语
func Hello(name string) (string, error) {
// 如果没有传递name,则返回错误
if name == "" {
return "", errors.New("empty name")
}
//使用随机的一组问候语
message := fmt.Sprintf(randomFormat(), name)
return message, nil
}

func Hellos(names []string) (map[string]string, error) {
// 新建map
messages := make(map[string]string)
// 遍历names,并调用Hello函数
for _,name := range names {
message, err := Hello(name)
if err != nil {
return nil, err
}
messages[name] = message
}
return messages, nil
}

// 设置初始值
func init() {
rand.Seed(time.Now().UnixNano())
}

//随机返回一组问候语
func randomFormat() string {
formats := []string{
"Hi, %v. Welcome!",
"Great to see youm %v",
"Hail, %v! Well met!",
}

return formats[rand.Intn(len(formats))]
}
  1. 编辑hello/hello.go文件,传递一组names到Hellos函数上
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

import (
"fmt"
"log"
"example.com/greetings"
)


func main() {
// 设置日志的属性
log.SetPrefix("greetings: ")
log.SetFlags(0)

names := []string{"Zerchin", "Zing", "xzq"}

message, err := greetings.Hellos(names)

// 错误处理
if err != nil {
log.Fatal(err)
}

fmt.Println(message)
}
  1. 执行代码
1
2
$ go run .
map[Zerchin:Hail, Zerchin! Well met! Zing:Hail, Zing! Well met! xzq:Hi, xzq. Welcome!]

七、代码单元测试

Go 的testing包和go test命令,您可以快速编写和执行测试。

  1. _test.go结尾的文件名告诉go test命令该文件包含测试函数,所以新建一个greetings_test.go文件,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package greetings

import (
"testing"
"regexp"
)

// 使用一个name调用greetings.Hello,检查是否返回有效值
func TestHelloName(t *testing.T) {
name := "Zerchin"
want := regexp.MustCompile(`\b` + name + `\b` )
msg, err := Hello("Zerchin")
if !want.MatchString(msg) || err != nil {
t.Fatalf(`Hello("Zerchin") = %q, %v, want match for %#q, nil`, msg, err, want)
}
}

// 调用greetings.Hello并传递空字符串,看是否返回错误
func TestHelloEmpty(t *testing.T) {
msg, err := Hello("")
if msg != "" || err == nil {
t.Fatalf(`Hello("") = %q, %v, want "", error`, msg, err)
}
}
  1. 执行go test命令进行测试
1
2
3
4
5
6
7
8
9
10
11
$ go test
PASS
ok example.com/greetings 0.005s

$ go test -v
=== RUN TestHelloName
--- PASS: TestHelloName (0.00s)
=== RUN TestHelloEmpty
--- PASS: TestHelloEmpty (0.00s)
PASS
ok example.com/greetings 0.007
  1. 修改greetings.go代码,假设代码有误,如下:
1
2
3
4
5
6
7
8
9
10
11
func Hello(name string) (string, error) {
// 如果没有传递name,则返回错误
if name == "" {
return "", errors.New("empty name")
}
//使用随机的一组问候语
//message := fmt.Sprintf(randomFormat(), name)
// 注释上一行,并新建这一行message,这里不传递name参数
message := fmt.Sprintf(randomFormat())
return message, nil
}
  1. 测试异常的结果
1
2
3
4
5
6
$ go test 
--- FAIL: TestHelloName (0.00s)
greetings_test.go:14: Hello("Zerchin") = "Hi, %!v(MISSING). Welcome!", <nil>, want match for `\bZerchin\b`, nil
FAIL
exit status 1
FAIL example.com/greetings 0.005s

八、编译并安装应用程序

  • go build:编辑包及其依赖项,但不安装
  • go install:编辑并安装软件包
  1. 进入到hello目录,执行go build命令将代码编译为可执行文件
1
go build
  1. 验证结果
1
2
$ ./hello 
map[Zerchin:Hail, Zerchin! Well met! Zing:Great to see youm Zing xzq:Hi, xzq. Welcome!]

此时可执行文件在当前目录下,需要手动执行路径才能执行

所以,可以通过go install命令将文件安装到go的PATH路径下

  1. 查看Go的安装路径
1
2
$ go list -f '{{.Target}}'
/Users/zerchin/go/bin/hello
  1. 添加该路径到PATH路径下
1
export PATH=$PATH:/Users/zerchin/go/bin/

可以通过 go env -w GOBIN=/path/to/your/bin命令设置环境变量修改安装路径

  1. 执行go install命令对代码进行编译和安装
1
go install
  1. 测试结果,可以直接执行hello命令
1
2
3
$ hello
map[Zerchin:Great to see youm Zerchin Zing:Great to see youm Zing xzq:Hi, xzq. Welcome!]