Go 语言初体验
安装好 Go 之后,就可以依照官网上的教程 How to Write Go Code 来了解如何用 Go 编程了。
创建工作目录
首先创建工作目录,然后设置 GOPATH 环境变量为该工作目录,最后将工作目录的子目录 bin 加入 PATH 环境变量中。
创建第一个程序
首先在工作目录中创建 Service-Computing-Homework 目录,用于存放源码。接着在该目录下创建 hello 目录,作为第一个程序的包目录。
在 hello 目录下创建 hello.go 文件:
package main
import "fmt"
func main() {
fmt.Printf("Hello, world.\n")
}
使用 Go 工具构建并安装该程序(由于之前设置了 GOPATH 环境变量,所以该指令可以在任何位置运行):
由于之前已经将 $GOPATH/bin
加入 PATH 环境变量中,所以可以直接输入 hello 执行相应的二进制程序:
顺便创建 Git 仓库并提交到 GitHub 上:
编写第一个库
现在来创建 stringutil 库,并让 hello 程序使用它。
用同样的方法创建 stringuil 子目录:
然后在该目录中创建 reverse.go 文件:
package stringutil
// Reverse returns its argument string reversed rune-wise left to right.
func Reverse(s string) string {
r := []rune(s)
for i, j := 0, len(r) - 1; i < len(r) / 2; i, j = i + 1, j - 1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}
通过 Go 工具编译该包:
修改 hello.go 程序如下:
package main
import (
"fmt"
"github.com/whichxjy/Service-Computing-Homework/stringutil"
)
func main() {
fmt.Printf(stringutil.Reverse("\n!oG ,olleH"))
}
使用 Go 工具构建并安装 hello(其依赖的 stringutil 也会自动安装):
输入 hello 执行相应的二进制程序,输出结果说明 stringutil 中的逆序函数对 hello.go 程序有效:
测试
此时可以用 testing 包进行测试。
在 stringutil 目录下创建 reverse_test.go 文件:
package stringutil
import "testing"
func TestReverse(t *testing.T) {
cases := []struct {
in, want string
}{
{"Hello, world", "dlrow ,olleH"},
{"Hello, 世界", "界世 ,olleH"},
{"", ""},
}
for _, c := range cases {
got := Reverse(c.in)
if got != c.want {
t.Errorf("Reverse(%q) == %q, want %q", c.in, got, c.want)
}
}
}
使用 go test 命令运行测试:
再创建一个库
以上的例子似乎过于简单了,下面我们再写一个快排算法来进一步熟悉 Go 语言的语法。
首先创建 qsort 目录:
然后在该目录下创建 qsort.go 文件:
注:Sortable 接口参考了 Go 源码中的 sort.go
package qsort
import (
"math/rand"
"time"
)
type Sortable interface {
// Len(data) => the length of data
Len() int
// Less(i, j) => check if data[i] is less than data[j]
Less(int, int) bool
// Swap(i, j) => swap data[i] and data[j]
Swap(int, int)
}
func Sort(data Sortable) {
qsort(data, 0, data.Len() - 1)
}
func qsort(data Sortable, left int, right int) {
if left < right {
// pivot index
pi := partition(data, left, right)
qsort(data, left, pi - 1)
qsort(data, pi + 1, right)
}
}
// Returns an int in [min, max)
func randomInt(min int, max int) int {
rand.Seed(time.Now().UnixNano())
return min + rand.Intn(max - min)
}
func partition(data Sortable, left int, right int) int {
// data[pivot] => element to be placed at right position
randIndex := randomInt(left, right + 1)
data.Swap(left, randIndex)
pivot := left
lower := left + 1
upper := right
for {
for lower < right && data.Less(lower, pivot) {
lower += 1
}
for upper > left && data.Less(pivot, upper) {
upper -= 1
}
if lower < upper {
data.Swap(lower, upper)
lower += 1
upper -= 1
} else {
break
}
}
// data[upper] is always smaller than pivot
data.Swap(left, upper)
return upper
}
接下来,创建 qsort_test.go 作为测试文件(其中 IntArr 实现了 Sortable 接口中规定的方法):
package qsort
import (
"testing"
"reflect"
)
type MyInt struct {
val int
}
type IntArr []MyInt
func (arr IntArr) Len() int {
return len(arr)
}
func (arr IntArr) Less(i int, j int) bool {
return arr[i].val < arr[j].val
}
func (arr IntArr) Swap(i int, j int) {
arr[i], arr[j] = arr[j], arr[i]
}
func TestSort(t *testing.T) {
cases := []struct {
in, want IntArr
} {
{IntArr{}, IntArr{}},
{IntArr{{1}}, IntArr{{1}}},
{IntArr{{3}, {4}, {1}, {2}, {5}}, IntArr{{1}, {2}, {3}, {4}, {5}}},
{IntArr{{123}, {-1}, {0}, {4}, {-10}}, IntArr{{-10}, {-1}, {0}, {4}, {123}}},
{IntArr{{10}, {9}, {8}, {7}, {6}, {5}, {4}, {3}, {2}, {1}, {0}},
IntArr{{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}}},
}
for _, c := range cases {
Sort(c.in)
if !reflect.DeepEqual(c.in, c.want) {
t.Errorf("Fail to sort %v\n", c.in)
}
}
}
最后,使用 go test 命令运行测试,输出结果表明测试全部通过。