开始编写GO

预览
  • Go程序员通常让所有的Go代码在一个单独的工作空间(workspace).
  • 一个工作空间包含很多版本控制仓库(比如,通过git管理)
  • 每个仓库包含一个或者多个包(packages).
  • 每个包由单独的目录下的Go源文件组成.
  • 包的目录路径决定他的导入路径

注意这是和其他编程环境不同的地方:每个项目都有单独的工作空间,并且工作空间与版本控制仓库紧密绑定

工作空间

工作根目录有两个目录:

  • src包含够源文件
  • bin包含可执行命令

go tool构建并安装binaries到bin目录

src子目录一般包含多个版本控制仓库(比如Git或者Mercurial)追踪一个或多个源包的开发。

下面展示工作空间的结构:

bin/
    hello                          # command executable
    outyet                         # command executable
src/
    github.com/golang/example/
        .git/                      # Git repository metadata
        hello/
            hello.go               # command source
        outyet/
            main.go                # command source
            main_test.go           # test source
        stringutil/
            reverse.go             # package source
            reverse_test.go        # test source
    golang.org/x/image/
        .git/                      # Git repository metadata
        bmp/
            reader.go              # package source
            writer.go              # package source
    ... (many more repositories and packages omitted) ...</pre>

上面的树显示工作空间包含两个仓库(exampleimage)。example仓库包含两个命令(hellooutyet)和一把库(stringutil). image仓库包含bmp包和其他的一些内容

经典的工作空间包含多个源仓库,源仓库包含多个包和命令。大多数的Go程序员将所有的Go源代码和依赖放在一个单独的工作空间。

注意,不应该使用symbolic links关联文件或者目录到工作空间。

GOPATH环境变量

GOPATH环境变量指定工作空间的位置。默认是在home目录里的go目录,比如Unix的$HOME/go,Windows的%USERPROFILE%\go(通常是C:\Users\YourName\go)。

如果想在不同的地方,可以使用set GOPATH指定目录的路径。(另一种通用的设置是GOPATH=$HOME).注意GOPATH一定不能是Go的安装目录。

go env命令打印当前有效的GOPATH,如果没有设置则打印默认的位置。

为了方便,添加工作空间的bin目录到你的路径:

$ export  PATH=$PATH:$(go env GOPATH)/bin

为了简短,接下来的文档使用GOPATH代替``(go env GOPATH)。

导入路径(Import paths)

import path是唯一的字符串表示包。包的导入路径对应工作空间里它的位置或者远程仓库位置。

标准库里的包具有简短的导入路径,比如fmtnet/http。对于你自己的包,指定的路径不能与标准库里的包或者其他内部包冲突。

如果你将代码保存在源文件仓库,那么应该使用源仓库的根目录作为你的基础路径。比如,如果你有Github账号,那么github.com/{user}就是你的基本路径。

注意不要再你能构建之前推送代码到远程仓库。

我们将使用github.com/{user}作为你的基础路径。在工作空间下创建一个目录保存源代码:

$ mkdir -p $GOPATH/src/github.com/user
第一个程序

要编译和运行一个简单的程序,先选择一个包路径(我们先用github.com/user/hello)并且在工作空间创建相应的包目录:

$ mkdir $GOPATH/src/github.com/user/hello

接下来,在这个目录下创建一个名为hello.go的文件,包含如下代码:

package main

import "fmt"

func main() {
    fmt.Println("Hello, world.")
}

现在就可以构建并安装程序了:

$ go install github.com/user/hello

现在你就可以在你的系统里运行这个命令了。go tool通过GOPATH指定的工作空间查找github.com/user/hello包的源代码

如果已经在包目录里,就可以省略掉包路径

$ cd $GOPATH/src/github.com/user/hello
$ go install

这个命令构建hello命令,产生一个可执行的binary。然后安装这个binary到工作空间下的bin目录,也就是$HOME/go/bin/hello

go tool只会在有错误的时候打印输出,所以如果没有内容产生,表示执行成功。

现在可以通过全路径运行程序

$ $GOPATH/bin/hello
Hello, world.
第一个库

现在我们编写一个library并且在hello程序里使用。

同样,第一步先选择一个包路径(我们使用github.com/user/stringutil)先,创建包路径

$ mkdir $GOPATH/src/github.com/user/stringutil

然后创建一个命为reverse.go的文件:

// Package stringutil contains utility functions for working with strings.
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 build测试包编译:

$ go build github.com/user/stringutil

如果已经在包源目录下,只需要:

go build

这不会产生输出文件。而是将编译完的包保存到本地构建缓存里。

现在修改hello.go来使用它:

package main

import (
      "fmt"
      "github.com/user/stringutil"
)

func main() {
        fmt.Println(stringutil.Reverse("!oG, olleH"))
}

install hello程序

$ go install github.com/user/hello

这一顿操作后,工作空间应该变成了:

bin/
    hello                 # command executable
src/
    github.com/user/
        hello/
            hello.go      # command source
        stringutil/
            reverse.go    # package source
Package names

Go源文件里的第一行一定是:

package name

其中name是包的默认名称。
(包中的所有文件必须使用相同的名称。)
Go的约定是报名是导入路径最后一个节点:crypto/rot13的包名是rot13

可执行命令的包名必须是package main

不要求包名称在链接到单个二进制文件的所有包中都是唯一的,只要导入路径(它们的完整文件名)是唯一的。

测试

Go有一个由go test命令和测试包组成的轻量级测试框架。

创建一个用_test.go结尾的文件,里面的方法命名为TestXXX。测试框架会运行每个方法;如果方法调用失败方法比如t.Error或者t.Fail,测试就被认为失败了。

创建一个$GOPATH/src/github.com/user/stringutil/reverse_test.go文件测试stringutil

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 test github.com/user/stringutil
ok      github.com/user/stringutil  0.165s
远程包

导入路径可以描述如何使用诸如Git或Mercurial之类的修订控制系统来获取包源代码。go tool使用该属性自动从远程仓库拉去包。比如,本文档里的实例就保存在github.com/golang/example。如果你在包的导入路径引入远程URL, go get将会自动获取,构建并且安装它:

$ go get github.com/golang/example/hello
$ $GOPATH/bin/hello
Hello, Go examples!

如果工作空间不存在指定的包,go get会将它放在GOPATH指定的第一个工作空间内。(如果包存在,go get会跳过远程获取,就和go install的行为一样了)

经过上面的操作后,工作目录结构将会变为:

bin/
    hello                           # command executable
src/
    github.com/golang/example
      .git/                       # Git repository metadata
        hello/
            hello.go                # command source
        stringutil/
            reverse.go              # package source
            reverse_test.go         # test source
    github.com/user/
        hello/
            hello.go                # command source
        stringutil/
            reverse.go              # package source
            reverse_test.go         # test source

Gihub上托管的hello命令依赖同一仓库下的stringutil包。hello.go文件里的imports使用相同的导入路径规范,所以go get命令可以定位并且安装起来的包:

import "github.com/golang/exmaple/stringutil"

规范是最简单的方式让你的Go包可以对其他的可用

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容