Go入门:怎样编写Go代码

Go入门:怎样编写Go代码

基本介绍

本文将描述如何开发一个简单的go包,并简单介绍go命令,以及获取、生成、安装go包和命令的标准方法。

代码结构

基本原则

  • 将所有Go代码放在一个工作空间(workspace)下。
  • 一个工作空间包含多个代码仓库。
  • 每个仓库有一个或多个包(packages)。
  • 每个包又包含一个或多个Go代码源文件。
  • 包的路径在import中体现。

工作空间(workspace)

每个工作空间根目录下包括:
- src Go源代码
- src文件夹下放置多个版本控制的仓库(项目)。
- pkg 包对象
- bin 生成的可执行文件
go命令编译源文件,并生产对应的结果文件到pkg和bin目录。

一个典型的go工作空间是这样子的:

上边的例子包括两个仓库、项目(example和image)。其中项目example包括两个命令(hello和outyet)和一个二进制库(stringutil);项目image包含bmp包和其它

一个典型的go工作空间包括多个代码库(由包和命令组成)。大多数程序员会把所有源代码和依赖放到一个工作空间。

各种不同的代码包编译生成命令和类库。这个我们以后单独讨论。

GOPATH环境变量

GOPATH环境变量又来标明你的工作空间的位置。大多数情况下也是开发Go代码唯一要设置的一个环境变量。

开始所有工作之前,你需要创建一个总的目录来当做工作空间,并且设置GOPATH变量指向这个目录。工作空间可以在任何目录下,在接下来的文档中我们使用home目录下的work目录 HOME/workhome HOME设为工作空间)
注意:工作目录不能跟Go的安装目录一样。

$ mkdir $HOME/work
$ export GOPATH=$HOME/work

方便起见,也会直接把工作空间下的bin目录添加到PATH路径(这样就可以在任意目录下直接执行生成的Go命令)。

$ export PATH=$PATH:$GOPATH/bin

点击这里获取更多关于GOPAT环境变量的设置帮助。

包路径

包路径用来唯一标记一个包,包路径反映了包在本地工作空间或远程代码库(接下来会详细说明)中的位置。

标准库中的包直接使用短包路径,比如“fmp”或“net/http”。但是对于自己编写的包,基础路径的名字不能与标准库和其它一些外部库冲突。

如果你的代码直接保存在一些版本控制的代码库里,应该直接使用代码库的根目录作为基本路径。比如,如果你的代码都存放在github的user用户下(github.com/user),那github.com/user就应该是基本路径。

即使你现在还没有打算把代码发布带远程代码仓库,最好还是按照以后准备提交代码仓库的方式组织代码结构。实际中可以使用任何组合来标记路径名称,只要对应的路径名称不与基本库冲突。

我们接下来将使用githun.com/user作为基本路径。在工作空间下创建对应的目录来保存代码:

$ mkdir -p $GOPATH/src/github.com/user

第一个Go程序

为了编译和运行一个简单的Go程序,需要在工作空间下创建包路径(我们接下来将使用github.com/user/hello)和对应的包目录。

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

接下来,在目录下新建一个hello.go文件,包含以下内容:

package main

import "fmt"

func main() {
    fmt.Printf("Hello, world.\n")
}

现在可以使用下边的go工具生成和安装这个程序:

$ go install github.com/user/hello

你可以在任何目录下执行上边的命令。go工具会根据GOPATH在对应工作空间下查找github.com/user/hello包。

你也可以忽略包路径而直接在对应代码包文件夹下执行go install命令:

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

以上命令会生成hello命令,同时产生可执行二进制文件。然后将对应的二进制命令安装到工作空间的bin目录下。在我们的这个例子中,会直接安装到 GOPATH/bin/hello HOME/work/bin/hello。

go命令执行成功时不会有任何输出,只有发生错误的时候才会打印对应的错误信息。

现在你可以在命令行中使用完整路径来执行这个程序:

$ $GOPATH/bin/hello
Hello, world.

或者,如果已经添加$GOPATH/bin到PATH,可以直接输入二进制名称来执行程序:

$ hello
Hello, world.

如果你正要使用版本控制系统,现在可以初始化代码仓库、添加文件,做第一次提交。再次强调,使用版本控制系统不是必须的。

$ cd $GOPATH/src/github.com/user/hello
$ git init
Initialized empty Git repository in /home/user/work/src/github.com/user/hello/.git/
$ git add hello.go
$ git commit -m "initial commit"
[master (root-commit) 0b4507d] initial commit
 1 file changed, 1 insertion(+)
  create mode 100644 hello.go

第一个库

接下来我们来写一个库给hello程序使用。

跟可执行程序一样,第一步还是创建包路径和对应的包文件夹。

$ 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:

$ go build

到这里还不会产生任何文件。你必须执行go insall命令生成输出库文件。

确认库文件已经产生后,就可以在之前的hello.go中使用这个库了:

package main

import (
    "fmt"

    "github.com/user/stringutil"
)

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

无论使用go安装包还是二进制文件,所有相关的依赖都会自动安装。所以当你安装hello程序时:

$ go install github.com/user/hello

对应的stringutil包也会自动被安装。

执行新的hello程序,你可以看到一个新的、已经被反转的消息:

$ hello
Hello, Go!

所有这些以后,你的工作空间应该是这样的:

bin/
    hello                 # command executable
pkg/
    linux_amd64/          # this will reflect your OS and architecture
        github.com/user/
            stringutil.a  # package object
src/
    github.com/user/
        hello/
            hello.go      # command source
        stringutil/
            reverse.go    # package source

注意:go install会把库文件stringutil.a放到pkg/linux_amd64下边(目录结构跟源代码结构一样)。这样可以go命令可以直接找到对应的包对象,避免不必要的重复编译。linux_amd64是为了根据操作系统和你的系统架构交叉编译。

所有Go可执行程序都通过静态方式链接在一起,所以在运行时是不需要相关的包对象(库)。

包命名

所有Go源代码都以下边的语句开始:

package name

其中name就是包引用是默认的名称。一个包中的所有文件必须使用同一个包名。

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

一个二进制文件下所有的包名不需要唯一,但是引用路径必须唯一。

了解更多关于Go的命名规范,可以参考实效Go编程

测试

Go自带了一个轻量级的测试框架,由go test命令和testing包组成。

你可以通过新建xx_test.go写一个测试,其中包含若干个TestXXX函数。测试框架会自动执行这些函数;如果函数中包含tError或t.Fail, 对应的测试会被判为失败。

添加一个针对stringutil的测试文件$GOPATH/src/github.com/user/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 test github.com/user/stringutil
ok      github.com/user/stringutil 0.165s

同样,在包文件夹下可以忽略包路径而直接执行go test命令:

$ go test
ok      github.com/user/stringutil 0.165s

远程包

包的引用路径用来描述如何通过版本控制系统获取包的源代码。go工具通过引用路径自动从远程代码仓库获取包文件。比如本文中用的例子也对应的保存在github.com/golang/example下。go可以通过包的代码仓库的url直接获取、生成、安装对应的包。

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

如果工作空间中不存在对应的包,go会将对应的包放到GOPATH环境变量指明的工作空间下。(如果包已经存在,go跳过代码拉去而直接执行go install)。

执行上边的go get命令后,工作空间文件夹下是这样的结果:

bin/
    hello                           # command executable
pkg/
    linux_amd64/
        github.com/golang/example/
            stringutil.a            # package object
        github.com/user/
            stringutil.a            # package object
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

github上的hello命令依赖于同个仓库下的stringutil库。hello.go使用同样的路径进行导入,所以go get命令能够直接找到并安装对应的依赖包。

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

这也是你共享Go包的最好方式。

关于go工具远程包的更多信息,可以参考Go - 导入路径帮助文档

接下来的事情

你可以订阅golang-announce邮件列表收取Go新版本的发布信息通知。

阅读高效Go编程来学习如何编写清晰、优雅的Go代码。

这里学习Go编程语言。

访问Go文档深入了解Go以及基本库和工具。

到这里就结束了,参考原文How to Write Go Code.

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值