Golang作为Docker、Kubernetes和OpenShift等一些酷辣新技术的编程语言,越来越受欢迎。尤其它们都是开源的,很多情况下,开源是非常有价值的。深入学习阅Golang等源代码库中的源文件,可以更深地理解它们,同时也有利于其他编程语言的开发者快速映射某些概念,比如Go与Java中常用概念的映射。本文的目的是帮助Java开发人员快速理解一些常见的Go习惯用法。
项目结构
Golang项目的一个常见约定是将所有cli二进制源文件或“main”包中的源文件放在根目录cmd文件夹下。通常可以在源根目录的pkg文件夹中找到实现了不同功能的内聚类型、常量、变量和函数集的包。
包
Golang将其代码组织成包,类似于Java。通过在源文件的顶部引入package来声明源文件所在的包(以及它的所有常量、类型、函数等)。但是与Java不同,不需要输入完整的包名+类名的路径,只需要输入包名即可。例如:
package api
假设有一个包“api/endpoint”,那么文件系统上就会有这个目录结构(例如:/pkg/api/endpoint),但是endpoint包在endpoint目录下的源文件中的声明,应该是这样的:
package endpoints
导入包
使用以下命令可以在程序中导入包,就像在Java中一样:
import (
stderrs "errors"
"time"
"Golang.org/x/net/context"
"k8s.io/kubernetes/pkg/auth/user"
)
可以根据包路径中的后一个包名在源代码中使用包。例如,在上面的例子中,我们导入k8s.io/kubernetes/pkg/auth/user,通过代码,可以用user.Foo()引用包中的元素。同样也可以在源文件中重命名包,这样它就不会与其他包名发生冲突,就像上面例子里所示:
import (
stderrs "errors"
)
并在自己的程序源码中直接引用stderrs.Foo()。
Main包
main包是Golang应用程序的入口点。main包必须有一个main()函数,该函数不接受参数,也不提供返回值。例如:
func main() { … }
如前所述,这个包通常位于根目录的cmd文件夹中。
类型、常量、函数的作用域/可见性
在Golang中,对于结构/类型/函数/变量在包外部的作用域和可见性,其标识符的首字符非常重要。例如,在一个foo包中,如果有一个名为func Bar()的函数,那么因为“Bar”的个字母是大写的,所以它在包之外是可用的(注:类似于java中的public)。因此,如果导入了foo包,就能够调用foo.Bar()函数。如果“bar”是小写的,它将被隐藏起来(类似于java中的private)。也就是说,个字母的大小写决定了其作用域与可见性。
方法可以返回多个值
Golang中的函数或方法(两者有区别)可以返回“元组”或多个值,与java有明显差异。例如,调用一个返回多个值的函数如下所示:
internalCtx, ok := foo.bar(context.Context)
其中,internalCtx表示函数内容,ok可表示函数调用成功或失败标识。
类、结构、方法
在Java中有类,但在Go中与之相似的概念是结构体(Struct)。struct也可以有成员和方法。如下所示:
type Rectangle struct {
width int
height int
}
这是一个名为“Rectangle”的数据结构,它有两个成员变量(也可以称为字段,原文中为fields):宽度和高度。可以像这样创建实例:
r := new(Rectangle)
还可以这样引用它的成员变量(fields):
r.width = 10
r.height = 5
我们可以在“Rectangle”数据结构上编写方法,如下所示:
func (r *Rectangle) area() int {
return r.width * r.height
}
这里的方法名称为area,可以这么来调用上面的方法:
r := new(Rectangle)
r.area()