Golang做为Docker、Kubernetes和OpenShift等一些酷辣新技术的首选编程语言,愈来愈受欢迎。尤为它们都是开源的,不少状况下,开源是很是有价值的。深刻学习阅Golang等源代码库中的源文件,能够更深地理解它们,同时也有利于其余编程语言的开发者快速映射某些概念,好比Go与Java中经常使用概念的映射。本文的目的是帮助Java开发人员快速理解一些常见的Go习惯用法。java

 

项目结构

Golang项目的一个常见约定是将全部cli二进制源文件或“main”包中的源文件放在根目录cmd文件夹下。一般能够在源根目录的pkg文件夹中找到实现了不一样功能的内聚类型、常量、变量和函数集的包。算法

 

Golang将其代码组织成包,相似于Java。经过在源文件的顶部引入package来声明源文件所在的包(以及它的全部常量、类型、函数等)。可是与Java不一样,不须要输入完整的包名+类名的路径,只须要输入包名便可。例如:编程

package apiapi

 

假设有一个包“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()

 

类型继承

Golang在设计上未采用Java的“继承(extends)”,它的继承是经过组合来完成的。例如:

type Rectangle struct {

Shape

width int

height int

}

上面Rectangle结构中有一个类型为Shape的匿名成员。Shape中包含的全部字段和方法在Rectangle对象上都是可见的。可是须要注意的是,不像在Java中,能够将Rectangle传递给Shape为参数的函数,这在Go中是行不通的。要得到这种类型的多态性,应该使用Go接口。

 

多态性、接口

在Java中有特定的接口类型,这些接口类型定义了对象的行为。在Go中,也有相似的概念,能够经过intefaces来实现。例如,下面这个接口声明了一个具备Print()方法的Shape类型:

type Shape interface {

Print()

当使用Go来建立结构时,不须要像在Java中那样用“implementation”来声明它。它是隐式的,只须要实现了该接口对应的方法,对应的结构体就能够被传递给须要的函数:

type Rectangle struct {

width int

height int

}

func (r *Rectangle) Print() {

fmt.println("Rectangle!");

}

此时,Rectangle对象能够传递给任何接收Shape类型的函数,由于它实现了该类型的全部方法。

 

For循环

Go中的For循环,样例以下:

for i := 1; i <= 10; i++ {

fmt.Println(i)

}

然而,当迭代一个数组(或相似于数组的东西,例如,字符串,映射,切片等),可使用range运算符(假设foo是一个列表List):

for v := range foo {

fmt.println("value="+v);

}

若是在遍历列表时须要知道该列表的索引,则能够这样编写代码:

for i, v := range foo {

fmt.println("index " + i +"has value="+v);

}

 

While循环

Go中还能够像这样再次使用for循环:

sum := 1

for sum < 1000 {

sum += sum

}

fmt.Println(sum)

或者实现一个无限while循环:

for {

something...

}

 

指针和引用

Golang中须要显式地使用指针和引用,而Java一般隐藏这些。例如,Java中能够这样作:

Shape shape = new Shape();

shape.foo(); 

可是在Go中,必须直接处理指针

type Rectangle struct {

width int

height int

}

func updateRectangle(r *Rectangle){

r.width = 5;

r.height = 10;

}

func main() {

r := Rectangle{20,30}

updateRectangle(&r)

}

当main函数执行完毕时,Rectangle对象中r.width=5,r.height=10。注意:必须显式地引用指针。

 

垃圾回收机制

Golang与java相似,也是一种垃圾收集语言。Go开发者不须要手动来释放程序中再也不使用的变量和结构占用的内存,在Go的运行时中有一个独立的进程,即垃圾收集器(GC),会处理这些事,它会经过标记算法搜索再也不使用的变量而后释放内存。

 

经过调用runtime.GC()函数能够显式的触发GC,但这只在某些特殊的场景下才会使用,好比当内存资源不足时调用runtime.GC(),它会在此函数执行的点上当即释放内存,此时程序可能会有短时的性能降低(因为GC进程的执行)。若是想知道当前的内存状态,也可使用以下代码:

var mruntime.MemStats

runtime.ReadMemStats(&m)

fmt.Printf("%dKb\n", m.Alloc / 1024)

上面的程序会给出已分配内存的总量,单位是 Kb。

 

 

原文做者:Christian Posta  译者:江玮

原文连接:https://dzone.com/articles/quick-go-lang-for-java-developers