JAVA开发者的Golang快速指南
Golang作為Docker、Kubernetes和OpenShift等一些酷辣新技術的首選編程語言,越來越受歡迎。尤其它們都是開源的,很多情況下,開源是非常有價值的。深入學習閱Golang等源代碼庫中的源文件,可以更深地理解它們,同時也有利于其他編程語言的開發者快速映射某些概念,比如Go與Java中常用概念的映射。本文的目的是幫助Java開發人員快速理解一些常見的Go習慣用法。
?
項目結構
Golang項目的一個常見約定是將所有cli二進制源文件或“main”包中的源文件放在根目錄cmd文件夾下。通??梢栽谠锤夸浀膒kg文件夾中找到實現了不同功能的內聚類型、常量、變量和函數集的包。
?
包
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()
?
類型繼承
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
版權聲明:本文版權歸作者(譯者)及公眾號所有,歡迎轉載,但未經作者(譯者)同意必須保留此段聲明,且在文章頁面明顯位置給出,本文鏈接如有問題,可留言咨詢。
轉載于:https://www.cnblogs.com/davidwang456/p/10327880.html
總結
以上是生活随笔為你收集整理的JAVA开发者的Golang快速指南的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpringBoot2.0新特性 - Q
- 下一篇: 一文揭秘定时任务调度框架quartz