Go语言已成为一种流行的非常流行编程语言,它是Docker、Kubernetes、OpenShift等一些炫酷新开源项目的首选编程语言,掌握Go语言意味着我们都可以为这些开源项目做贡献。
我在日常学习中学习过很多编程语言,例如C,C++,C#,Java,Python,Scala,Groovy,Assembly,JavaScript等。我花了几周的时间学习Go语言和阅读Docker、Kubernetes、OpenShift的源代码。我认为对于一个程序员来说,学习另外一种新的编程语言,可以将你所熟悉的编程语言(例如Java)中的概念带入新的编程语言中,这对你学习新的编程语言有很大的帮助和参考意义。
本文当然不是单纯的Go语言的简介,也不是完整的Java-Go的映射。本文的目的是快速帮助Java开发人员快速的了解和入门Go语言开发。
项目结构在Go语言项目中,通常直接将源代码放到项目的根目录中,而不是像Java那样将源码放入项目的src目录中。在项目根目录中也可以根据业务划分不同的package。
Packages与Java类似,Go语言将其代码组织到package中。您可以通过packagepackage_name在源码的顶部来声明源文件所在的package(及其所有常量,类型,函数等);但是与Java不同,你不需要不输入完整package路径,只用输入包名即可。例如:
packageapi
所以,如果你的包名为:“api/endpoints”,那么对应文件系统上的目录结构就是“./pkg/api/endpoints”,endpoints包在源代码中声明方式如下:
packageendpoints
这点要和Java区分开,如果按照Java的包声明规则,那么声明可能就是下面这种了:
//注意这是错误的声明方式packageapi.endpoints导入Packages
Go语言和Java一样,可以通过import的方式导入package,在Go语言中导入包的方式如下:
import(stderrs"errors""time""golang.org/x/net/context""k8s.io/kubernetes/pkg/auth/user")
我们可以根据包路径中的最后一个包名称在源代码中使用包。例如在上面的示例中,我们导入了包k8s.io/kubernetes/pkg/auth/user,那么在代码中可以可以使用user.xxx调用该包下的静态方法、类、常量,例如:user.Foo()。如果我们想在源文件中重命名包,以免与其他名称冲突,那么可以使用下面这种方式:
import(stderrs"errors")
那么我们在代码中调用errors包下的程序就需要通过别名,例如:stderrs.Foo()
main包main包是Go语言的应用程序入口点。main包中必须有一个main()函数,它没有参数和返回值:
funcmain(){…}
这个main函数就是项目的启动入口。
类型、常量、函数的的作用域Go语言中没有类似Java中private、protected、public关键字,Go语言是通过命名的首字母大小写来定义struct/type/function/variable的作用域。首字母小写表示private、大写表示public。
例如,在foo包中,如果你有一个这样的函数funcBar(),由于“Bar”的首字母大写,因此可以在包外部调用。如果你导入foo包,则可以访问foo.Bar()。如果将函数修改为首字母小写:funcbar(),那么包外是无法访问该函数的。
函数支持多返回值Go语言中的函数(可以理解为Java中的方法)可以有多个返回值。例如,调用返回多个值的函数如下所示:
//函数定义funcfoo()(string,bool){...}//函数调用str,ok:=foo()
其中:str和ok为foo的两个返回值。
类,结构,方法在Java中我们有class,Go语言中是没有class的,但是有和class概念、作用相似的东西:结构体(struct)。在struct中可以定义函数和成员变量。
例如:
typeRectanglestruct{widthintheightint}
这是一个名为Rectangle的struct,具有两个字段:width和height。我们可以这样创建一个新的Rectangle:
r:=new(Rectangle)
我们可以像下面这样访问他的字段:
r.width=10r.height=5
我们可以像下面这样为结构体添加方法:
func(r*Rectangle)area()int{returnr.width*r.height}类型继承
Go语言不想Java那样有关键字extends来实现类的继承。类型的继承是匿名字段组合来完成的。如下:
typeRectanglestruct{Shapewidthintheightint}
这这个示例中,Rectangle有一个匿名字段Shape,那么Shape中的字段和方法都会在Rectangle对象中可见。
需要注意的是,如果一个函数的要求的参数是Shape,虽然Rectangle继承自Shape,也不能直接将Rectangle对象作为该函数的参数。这点是和Java不同的,Java中是允许将更具体的子类型作为参数的。如果要想实现类型的多态,请使用Go语言中的接口(下个章节会讲到)
多态、接口在Java中,我们有特定的接口类型:interface,接口中的方法由继承了该接口的class来具体实现。Go语言同样有接口功能,但是Go语言中接口的实现是不需要显式的去声明,只需要结构体(即Java中的类)去实现接口中方法即可。
如下,有一个Shape接口,该接口中声明了函数Print()
typeShapeinterface{Print()}
当我们创建我们的结构体时,我们不用像在Java中那样通过“implements”来声明它。我们只需实现Shape接口中的方法,Go语言就会认为该结构体实现类Shape接口,例如:
typeRectanglestruct{widthintheightint}func(r*Rectangle)Print(){fmt.println("Rectangle!");}
在这种情况下,Rectangle对象可以传递给参数为Shape类型的函数了,因为Rectangle实现了Shape所有的方法。
for循环GO语言循环例子:
fori:=1;i=10;i++{fmt.Println(i)}
当迭代数组(或者字符串、map、slice等等)时,可以使用range来进行迭代,假设foo是一个列表,那么迭代方式如下:
forv:=rangefoo{fmt.println("value="+v);}
如果你需要在迭代过程中获取数据的索引,那么可以使用以下方式:
fori,v:=rangefoo{fmt.println("index"+i+"hasvalue="+v);}while循环
Go语言中没有while循环,但是你可以使用for循环来实现while循环相同的功能,如下:
sum:=1forsum{sum+=sum}fmt.Println(sum)
下面是无限循环的例子:
for{something...}指针与引用
Java中值类型和引用类型都是隐式的,int、double、float、long、byte、short、char、boolean为值类型,其他的都是引用类型,而Go语言中却不是这样。
在Go语言中:
表示取地址,例如你有一个变量a那么a就是变量a在内存中的地址,对于Golang指针也是有类型的,比如a是一个string那么a是一个string的指针类型,在Go里面叫string。*表示取值,接上面的例子,假设你定义b:=a如果你打印b,那么输出的是a的内存地址,如果要取值,那么需要使用:*b下面我们来看一个例子:
packagemainimport("fmt")funcmain(){a:=""b:=afmt.Println(a)fmt.Println(b)fmt.Println(*b)}输出结果为:0x40c128垃圾回收
和Java一样,Go语言是有自己的垃圾回收机制的,不需要我们显式的释放内存,垃圾回收机制能够大大的减轻开发的复杂度。
本文由码农俱乐部[1]翻译自:白癜风药物治疗能好吗白癫风