Go 语言初体验

项目地址:Service-Computing-Homework

安装好 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 命令运行测试,输出结果表明测试全部通过。

Updated: