golang基础之工程结构

Golang 工作空间

编译工具对源码目录有严格要求,每个工作空间 (workspace) 必须由 bin、pkg、src 三个目录组成。

workspace
    |
    +--- bin                // go install 安装目录。
    |   |
    |   +--- learn
    |
    +--- pkg。             // go build 生成静态库 (.a) 存放目录。
    |     |
    |     +--- darwin_amd64 
    |               |
    |               +--- mylib.a 
    |               |
    |               +--- mylib 
    |                      |
    |                      +--- sublib.a
    |   
    +--- src            // 项目源码目录。
    |
    +--- learn
    |      |
    |      +--- main.go
    |  
    +--- mylib
           |        
           +--- mylib.go
           |        
           +--- sublib
                   |
                   +--- sublib.go

可在 GOPATH 环境变量列表中添加多个工作空间,但不能和 GOROOT 相同。

export GOPATH=$HOME/projects/golib:$HOME/projects/go

通常 go get使用第一个工作空间保存下载的第三方库。

Golang目前有很多很多个标准的包,覆盖了几乎所有的基础库。

golang.org有所有包的文档。

Golang 源文件

编码:源码文件必须是 UTF-8 格式,否则会导致编译器出错。

结束:语句以 ";" 结束,多数时候可以省略。

注释: 持 "//"、"/**/" 两种注释方式,不能嵌套。

命名:采用 camelCasing 风格(驼峰命名法),不建议使用下划线。

Golang 包结构

所有代码都必须组织在 package 中。

• 源文件头部以 "package <name>" 声明包名称。
• 包由同一目录下的多个源码文件组成。
• 包名类似 namespace,与包所在目录名、编译文件名无关。 
• 目录名最好不用 main、all、std 这三个保留名称。
• 可执行文件必须包含 package main,入口函数 main。

说明:os.Args 返回命令行参数,os.Exit 终止进程。要获取正确的可执行文件路径,可用 filepath.Abs(exec.LookPath(os.Args[0]))

package 基本的管理单元:

同一个package下面,可以有非常多的不同文件,只要每个文件的头部 都有 如 "package xxx" 的相同name 就可以 在主方法中使用 xxx.Method()调用不同文件中的方法了。 文件夹名字可以和这个package 名称不一致, 比如我有个文件夹名字是mypackage,其中包含了a.go,b.go, c.go三个文件 :

mypackage   
  | --a.go
  | --b.go
  | --c.go

比如a.go中有 Saya(),b.go中有Sayb() 而几个文件共同的package name 确是testpackage

所以在 主函数中调用a.go 和b.go文件中的各自方法只要用,testpackage.Saya() ,testpackage.Sayb()即可 还有默认的init方法,在import进来的时候就去执行了,而且允许每个文件中都有init()这个方法,当然是每个都会执行。

导出包: 在 Go 中,包中成员以名称首字母大小写决定访问权限。首字母大写的名称是被导出的。

在导入包之后,你只能访问包所导出的名字,任何未导出的名字是不能被包外的代码访问的。

Foo 和 FOO 都是被导出的名称。名称 foo 是不会被导出的。

• public: 首字母大写,可被包外访问。
• internal: 首字母小写,仅包内成员可以访问。

该规则适用于全局变量、全局常量、类型、结构字段、函数、方法等。

导入包 :使用包成员前,必须先用 import 关键字导入,但不能形成导入循环。

import "相对目录/包主文件名"

相对目录是指从<workspace>/pkg/<os_arch>开始的子目录,以标准库为例:

import "fmt"      ->  /usr/local/go/pkg/darwin_amd64/fmt.a
import "os/exec"  ->  /usr/local/go/pkg/darwin_amd64/os/exec.a

在导入时,可指定包成员访问方式。比如对包重命名,以避免同名冲突。

import 用法:

import "fmt"        最常用的一种形式(系统包)
import "./test"     导入同一目录下test包中的内容(相对路径)
import "shorturl/model  加载gopath/src/shorturl/model模块(绝对路径)
import f "fmt"      导入fmt,并给他启别名f
import . "fmt"      将fmt启用别名".",这样就可以直接使用其内容,而不用再添加fmt。
    如fmt.Println可以直接写成Println
import  _ "fmt"     表示不使用该包,而是只是使用该包的init函数,并不显示的使用该包的其他内容。
    注意:这种形式的import,当import时就执行了fmt包中的init函数,而不能够使用该包的其他函数。

未使用的导入包,会被编译器视为错误 (不包括 "import _")。

./main.go:4: imported and not used: "fmt"

自定义路径 :可通过 meta 设置为代码库设置自定义路径。

server.go

package main

import (
    "fmt"
    "net/http" 
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, `<meta name="go-import"
                   content="test.com/qyuhen/test git https://github.com/qyuhen/test">`)
}

func main() {
    http.HandleFunc("/qyuhen/test", handler)
    http.ListenAndServe(":80", nil)
}

该示例使用自定义域名 test.com 重定向到 github。

$ go get -v test.com/qyuhen/test

Fetching https://test.com/qyuhen/test?go-get=1
https fetch failed.
Fetching http://test.com/qyuhen/test?go-get=1
Parsing meta tags from http://test.com/qyuhen/test?go-get=1 (status code 200)
get "test.com/qyuhen/test": found meta tag http://test.com/qyuhen/test?go-get=1
test.com/qyuhen/test (download)
test.com/qyuhen/test

如此,该库就有两个有效导入路径,可能会导致存储两个本地副本。为此,可以给库添加专门的 "import comment"。当 go get 下载完成后,会检查本地存储路径和该注释是否一致。

github.com/qyuhen/test/abc.go

package test // import "test.com/qyuhen/test"

func Hello() {
    println("Hello, Custom import path!")
}

如继续用 github 路径,会导致 go build 失败。

$ go get -v github.com/qyuhen/test

github.com/qyuhen/test (download)
package github.com/qyuhen/test
    imports github.com/qyuhen/test
    imports github.com/qyuhen/test: expects import "test.com/qyuhen/test"

这就强制包用户使用唯一路径,也便于日后将包迁移到其他位置。

Golang初始化

初始化函数:

    • 每个源文件都可以定义一个或多个初始化函数。 
    • 编译器不保证多个初始化函数执行次序。
    • 初始化函数在单一线程被调 ,仅执行一次。 
    • 初始化函数在包所有全局变量初始化后执行。 
    • 在所有初始化函数结束后才执行 main.main()。 
    • 无法调用初始化函数。

因为无法保证初始化函数执行顺序,因此全局变量应该直接用 var 初始化。

var now = time.Now()

func init() {
    fmt.Printf("now: %v\n", now)
}

func init() {
    fmt.Printf("since: %v\n", time.Now().Sub(now))
}

可在初始化函数中使用 goroutine,可等待其结束。

var now = time.Now()

func main() {
    fmt.Println("main:", int(time.Now().Sub(now).Seconds()))
}

func init() {
    fmt.Println("init:", int(time.Now().Sub(now).Seconds()))
    w := make(chan bool)

    go func() {
        time.Sleep(time.Second * 3)
        w <- true
    }()

    <-w 
}

输出:

init: 0
main: 3

不应该滥用初始化函数,仅适合完成当前文件中的相关环境设置。

Golang 文档

扩展工具 godoc 能自动提取注释生成帮助文档。

• 仅和成员相邻 (中间没有空行) 的注释被当做帮助信息。 
• 相邻行会合并成同一段落,用空行分隔段落。
• 缩进表示格式化文本,比如示例代码。
• 自动转换 URL 为链接。
• 自动合并多个源码文件中的 package 文档。 
• 无法显式 package main 中的成员文档。

Package

• 建议用专门的 doc.go 保存 package 帮助信息。
• 包文档第一整句 (中英文句号结束) 被当做 packages 列表说明。

Example

只要 Example 测试函数名称符合以下规范即可。

格式

示例

package

Example, Example_suffix

Example_test

func

ExampleF, ExampleF_suffix

ExampleHello

type

ExampleT, ExampleT_suffix

ExampleUser, ExampleUser_copy

method

ExampleT_M, ExampleT_M_suffix

ExampleUser_ToString

说明:使用 suffix 作为示例名称,其首字母必须小写。如果文件中仅有一个 Example 函数,且调用了该文件中的其他成员,那么示例会显示整个文件内容,而不仅仅是测试函数自己。

Bug

非测试源码文件中以 BUG(author) 开始的注释,会在帮助文档 Bugs 节点中显示。

// BUG(yuhen): memory leak.

欢迎您关注程序员同行者订阅号,程序员同行者是一个技术分享平台,主要是运维自动化开发:linux、python、django、saltstack、redis、golang、docker、kubernetes、vue等经验分享及经验交流。

趁现在,关注我们

牛人并不可怕,可怕的是牛人比我们还努力!

如果您觉得不错,请别忘了转发、分享、点赞让更多的人去学习, 您的举手之劳,就是对小编最好的支持,非常感谢!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏VRPinea

1.18 VR扫描:Facebook或将发布AR产品;广东联通打通全球首个5G手机电话

近日,印度教育科技公司Byju’s宣布,以1.2亿美元收购主打AR教育游戏的美国硅谷初创公司Osmo。Osmo的AR游戏可结合定制化的实体玩具供儿童玩乐,其利用...

9920
来自专栏bboysoul

树莓派安装go

大学的时候在使用openfalcon的时候讲过这个东西,但是那时候是介绍open-falcon的,所以感觉不是很具体,所以今天在安装frp的时候也碰到了这个问题...

20740
来自专栏AI科技大本营的专栏

Google发布新的问答语料库,专攻篇章级的NLU问题

开放域的问答(QA)是自然语言理解(NLU)中的一项基本任务,旨在模拟人是如何通过阅读和理解完整的文档,从而寻找信息、发现问题的答案。例如,对于“天空为什么是蓝...

10230
来自专栏日常学python

一个网络请求的冒险之旅

对于互联网,人们总是高谈阔论,却很少有人愿意去了解电脑、手机、电视这些设备到底是如何被“连接”起来的。

10520
来自专栏奇点大数据

这份“插件英雄榜Top9”才是Chrome的正确打开方式!

说到这个插件的作用,如果在没有特殊使用需求时,真的是无感。不过,有些插件使用习惯后,就发现确实很好用,而且潜移默化的改变你的使用习惯,引用作者的话“插件是 Ch...

13820
来自专栏VRPinea

1.15 VR扫描:NextVR将进行裁员;华纳兄弟与英特尔联手打造自动驾驶汽车娱乐体验

日前,直播VR公司NextVR进行了裁员。其并未申请《根据加利福尼亚州的法律声明有关于减少劳动力》的通知,表明裁员的规模未达披露的门槛。此外,该公司联合创始人兼...

13130
来自专栏阶梯计划

Alpine linux容器中运行go的二进制文件

将golang编译的二进制文件 opena 拷贝到容器的 /usr1 下面,执行显示:

62540
来自专栏C/C++基础

Go AES加解密

https://blog.csdn.net/K346K346/article/details/89387460

25230
来自专栏C/C++基础

Golang import包时可以使用相对路径吗

但是从Go 1.10开始,可以畅通无阻地使用相对路径来import包,即如下的包导入方式将不会出错。

43150
来自专栏用户5290714的专栏

一起来捉妖:腾讯的首款区块链游戏?|DApp101

《一起来捉妖》这款游戏其实墨鲫在去年就有看到腾讯发布的白皮书,但当时已经是内测通道关闭的时候,因此只好安心等公测。前几天这款游戏终于公测了,并且发布后迅速登顶A...

18630

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励