zoukankan      html  css  js  c++  java
  • go工程组织规范

    go编码以workspace形式管理,一个workspace包含所有的Go编码,包含多个版本控制仓库(例如使用git管理的多个仓库)。每个仓库包含多个包package,每个package是一个单独的路径,包含所有go源码,包的路径就是包的导入路径(import path)。

    1. Workspace

    Workspace作为根目录,包含两个目录src和bin。bin包含可执行文件,src包含源码。典型的src包含多个版本控制仓库(记录源码开发过程)。形如:

     

    上面的workspace包含两个仓库example和image。example包含两个命令(或包,hello和outyet)和一个库(或包,stringutil)。

    $GOPATH指向当前的Workspace。

    包的导入路径(import path),指定一个包在workspace或远程仓库的位置。标准库的导入路径可以简写,如“fmt”和“net/http”。但自有库的包的导入路径应该是绝对路径(src下级路径开始),包含基础路径(如:github.com/user)。可通过go help importpath获取更多导入路径的信息。

    go源码的第一有效行(注释行除外)必须是

    package name

    name是导入路径(import path)的默认包名。在一个包中所有文件必须用相同包名,惯例:导入路径名的最后一项应与包名相同,以方便识别和记忆,不出错。

    一个程序只有一个main包,一个包中只能有一个main函数,不能重复定义。

    对一个可执行程序,不要求package名唯一,但要求导入路径唯一(即可明确确认一个包)。

    go程序导出名字

    在 Go 中,任何以大写字母开头的变量或者函数都是被导出的名字。其它包只能访问被导出的函数和变量。

    同一个包中,所有变量和函数都可调用,无论首字母是否大小写。

    first程序

    用自己的github账号创建仓库路径:$GOPATH/src/github.com/yuxi-o/golang,此目录下创建包目录hello,然后在hello目录下创建hello.go程序。

    目前hello.go路径为:src/github.com/yuxi-o/golang/hello/hello.go。

    现在运行如下命令安装hello.go程序:

    $go install github.com/yuxi-o/golang/hello

    注意:go install或go build执行的路径为package路径,可执行程序名为包路径名。

    可采用git管理yuxi-o/golang仓库,在golang目录下:

    ~/go/src/github.com/yuxi-o/golang$ ls
    hello
    ~/go/src/github.com/yuxi-o/golang$ git init
    Initialized empty Git repository in /home/wang/go/src/github.com/yuxi-o/golang/.git/
    ~/go/src/github.com/yuxi-o/golang$ git add .
    ~/go/src/github.com/yuxi-o/golang$ git commit -m "first go program"
    [master (root-commit) bd2635a] first go program
     1 file changed, 6 insertions(+)
     create mode 100644 hello/hello.go

     

    first库

    mkdir $GOPATH/src/github.com/yuxi-o/golang/stringutil
    cat ~/go/src/github.com/yuxi-o/golang/stringutil/reverse.go 
    package stringutil
    
    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 github.com/yuxi-o/golang/stringutil

    注:go build编译库不会输出文件,保存编译包到local build cache。

    cat ~/go/src/github.com/yuxi-o/golang/hello/hello.go 
    package main
    import (
        "fmt"
        "github.com/yuxi-o/golang/stringutil"
    )
    
    func main() {
    //    fmt.Println("Hello, Go world")
        fmt.Println(stringutil.Reverse("!oG, olleH"))
    }
    $go install github.com/yuxi-o/golang/hello

    现在目录如下:

    go测试

    go提供轻量级测试框架,包含go test和testing package。

    go测试文件命令为_test.go,测试函数定义:func TestXXX(t *testing.T)。test框架运行每个测试函数。假如测试失败,返回t.Error或t.Fail。

    cat ~/go/src/github.com/yuxi-o/golang/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, wang %q", c.in, got, c.want)
            }
        }
    }
    $ go test github.com/yuxi-o/golang/stringutil
    ok      github.com/yuxi-o/golang/stringutil    0.002s

    Remote包

    导入路径可以描述怎样获取package源码(通过git或mercurial)。go get可以fetch、build和install包,若包不存在,go get会下载包到第一个workspace。可下载golang/example测试:

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

    2. go项目结构

    go项目体检的目录结构:golang-standards/project-layout

    ├── LICENSE.md
    ├── Makefile
    ├── README.md
    ├── api
    ├── assets
    ├── build
    ├── cmd
    ├── configs
    ├── deployments
    ├── docs
    ├── examples
    ├── githooks
    ├── init
    ├── internal
    ├── pkg
    ├── scripts
    ├── test
    ├── third_party
    ├── tools
    ├── vendor
    ├── web
    └── website

    /pkg

    这个目录中存放的就是项目中可以被外部应用使用的代码库,其他的项目可以直接通过 import 引入这里的代码,所以当我们将代码放入 pkg 时一定要慎重,建议各位开发者对项目中公有和私有的代码进行妥善的划分。

    /internal

    私有代码推荐放到 /internal 目录中,真正的项目代码应该写在 /internal/app 里,同时这些内部应用依赖的代码库应该在 /internal/pkg 子目录和 /pkg 中,下图展示了一个使用 /internal 目录的项目结构: 

    当我们在其他项目引入包含 internal 的依赖时,Go 语言会在编译时报错:

    An import of a path containing the element “internal” is disallowed

    if the importing code is outside the tree rooted at the parent of the "internal" directory.

    这种错误只有在被引入的 internal 包不存在于当前项目树中才会发生,如果在同一个项目中引入该项目的 internal 包并不会出现这种错误。

    /src

    在 Go 语言的项目最不应该有的目录结构其实就是 /src 了,社区中的一些项目确实有 /src 文件夹,但是这些项目的开发者之前大多数都有 Java 的编程经验,这在 Java 和其他语言中其实是一个比较常见的代码组织方式,但是作为一个 Go 语言的开发者,我们不应该允许项目中存在 /src 目录。

    最重要的原因其实是 Go 语言的项目在默认情况下都会被放置到 $GOPATH/src 目录下,这个目录中存储着我们开发和依赖的全部项目代码,如果我们在自己的项目中使用 /src 目录,该项目的 PATH 中就会出现两个 src

    $GOPATH/src/github.com/draveness/project/src/code.go

    上面的目录结构看起来非常奇怪,这也是我们在 Go 语言中不建议使用 /src 目录的最重要原因。

    平铺

    另一种在 Go 语言中组织代码的方式就是项目的根目录下放项目的代码,这种方式在很多框架或者库中非常常见,如果想要引入一个使用 pkg 目录结构的框架时,我们往往需要使用 github.com/draveness/project/pkg/somepkg,当代码都平铺在项目的根目录时只需要使用 github.com/draveness/project,很明显地减少了引用依赖包语句的长度。

    所以对于一个 Go 语言的框架或者库,将代码平铺在根目录下也很正常,但是在一个 Go 语言的服务中使用这种代码组织方法可能就没有那么合适了。

    /cmd

    /cmd 目录中存储的都是当前项目中的可执行文件,该目录下的每一个子目录都应该包含我们希望有的可执行文件,如果我们的项目是一个 grpc 服务的话,可能在 /cmd/server/main.go 中就包含了启动服务进程的代码,编译后生成的可执行文件就是 server

    我们不应该在 /cmd 目录中放置太多的代码,我们应该将公有代码放置到 /pkg 中并将私有代码放置到 /internal 中并在 /cmd 中引入这些包,保证 main 函数中的代码尽可能简单和少。

    /api

    /api 目录中存放的就是当前项目对外提供的各种不同类型的 API 接口定义文件了,其中可能包含类似 /api/protobuf-spec/api/thrift-spec 或者 /api/http-spec 的目录,这些目录中包含了当前项目对外提供的和依赖的所有 API 文件:

    $ tree ./api
    api
    └── protobuf-spec
        └── oceanbookpb
            ├── oceanbook.pb.go
            └── oceanbook.proto

    二级目录的主要作用就是在一个项目同时提供了多种不同的访问方式时,用这种办法避免可能存在的潜在冲突问题,也可以让项目结构的组织更加清晰。

    Makefile

    最后要介绍的 Makefile 文件也非常值得被关注,在任何一个项目中都会存在一些需要运行的脚本,这些脚本文件应该被放到 /scripts 目录中并由 Makefile 触发,将这些经常需要运行的命令固化成脚本减少『祖传命令』的出现。

    参考:

    1. How to write Go Code  https://golang.google.cn/doc/code.html

    2. https://golang.google.cn/ 提供go在线测试环境和文档

    3. https://golang.google.cn/doc/ go相关文档

    4. https://golang.google.cn/pkg/ go标准库

    5. go基础学习 coder python修行路

    6.  可在https://godoc.org/中搜索所有golang库的接口说明。

    7. 在 GitHub 上构建一个看上去正规的 Golang 项目

    8. 如何写出优雅的 Go 语言代码 

  • 相关阅读:
    古谚、评论与论断、名篇与名言
    重读《西游记》
    重读《西游记》
    命名之法 —— 时间、季节、地点
    命名之法 —— 时间、季节、地点
    文言的理解 —— 古时的称谓、别称、别名
    文言的理解 —— 古时的称谓、别称、别名
    Oracle GoldenGate for Oracle 11g to PostgreSQL 9.2.4 Configuration
    瀑布 敏捷 文档
    POJ 1325 ZOJ 1364 最小覆盖点集
  • 原文地址:https://www.cnblogs.com/embedded-linux/p/10878049.html
Copyright © 2011-2022 走看看