為Java程式設計師準備的Go教程:快速入門

2021-02-19 Go語言中文網

Golang從09年發布,中間經歷了多個版本的演進,已經漸漸趨於成熟,並且出現了很多優秀的開源項目,比如我們熟知的docker,etcd,kubernetes等,其媲美於C的性能、Python的開發效率,又被稱為21世紀的C語言,尤其適合開發後臺服務。這篇文章主要是介紹Golang的一些主要特性,和Java做一個對比,以便更好的理解Golang這門語言。

關於Golang環境的搭建就不講了,可以參考官方文檔或者Google一下,配置下SDK和PATH即可,非常簡單,我們就從Go版本的Hello World開始

Hello World

每種語言都有自己的Hello World,Go也不例外,Go版本的如下:

package mainimport "fmt"func main() {

   fmt.Println("Hello, 世界")
}

我們使用go run運行後,會在控制臺終端看到Hello, 世界的輸出。我們來看下這段代碼:

package 是一個關鍵字,定義一個包,和Java裡的package一樣,也是模塊化的關鍵。

main包是一個特殊的包名,它表示當前是一個可執行程序,而不是一個庫。

import 也是一個關鍵字,表示要引入的包,和Java的import關鍵字一樣,引入後才可以使用它。

fmt是一個包名,這裡表示要引入fmt這個包,這樣我們就可以使用它的函數了。

main函數是主函數,表示程序執行的入口,Java也有同名函數,但是多了一個String[]類型的參數。

Println是fmt包裡的函數,和Java裡的system.out.println作用類似,這裡輸出一段文字。

整段代碼非常簡潔,關鍵字、函數、包等和Java非常相似,不過注意,go是不需要以;(分號)結尾的。

變量

go語言變量的聲明和java的略有不同,以聲明一個int類型,變量名為age為例,go語言變量生成如下:

var age int =10

同樣的變量,在java中的聲明是:

int age = 10;

可以看到go的變量聲明,修飾變量的類型在變量的後面,而且是以var關鍵字開頭。

var 變量名 類型 = 表達式

最後面的賦值可以在聲明的時候忽略,這樣變量就有一個默認的值,稱之為零值。零值是一個統稱,以類型而定,比如int類型的零值為0,string類型的零值是」」空字符串。

在go中除了以var聲明變量之外,還有一種簡短的變量聲明方式:=,比如上面例子,可以如下簡單聲明:

age := 10

這種方式和上面的例子等價,但是少了var和變量類型,所以簡短方便,用的多。使用這種方式,變量的類型由go根據值推導出來,比如這裡默認是int。

常量

有了變量,就少不了常量,和var關鍵字不一樣,go的常量使用const聲明,這個和C裡的常量一樣。

const age = 10

這樣就聲明了一個常量age,其值是10,因為我們這裡沒有指定常量的類型,所以常量的類型是根據值推導出來的。所以等價的我們也可以指定常量類型,如下:

const age int = 10

相比來說,java下的常量定義就要複雜一些,要有static final修飾符,才是常量:

private static  final int AGE = 10;

這個和go的實現等價,但是它的定義修飾符比go多多了,而且常量類型不能省略。

大小寫標記訪問權限

我們上面的go例子中我特意用了小些的變量名age,甚至常量我也沒有寫成AGE,但是在java中,對於常量我們的習慣是全部大些。

在go中不能隨便使用大小寫的問題,是因為大小寫具有特殊意義,在go中,大些字母開頭的變量或者函數等是public的,可以被其他包訪問;小些的則是private的,不能被其他包訪問到。這樣就省去了public和private聲明的煩惱,使代碼變的更簡潔。

特別說明,這些導出規則只適用於包級別名字定義,不能使函數內部的定義。

包的規則和java很像,每個包都有自己獨立的空間,所以可以用來做模塊化,封裝,組織代碼等。
和java不同的是,go的包裡可以有函數,比如我們常用的fmt.Println(),但是在在java中沒有這種用法,java的方法必須是屬於一個類或者類的實例的。

要使用一個包,就需要先導入,使用import關鍵字,和java也一樣,可以參見前面的helloworld示例。

如果我們需要導入多個包的時候,可以像java一樣,一行行導入,也可以使用快捷方式一次導入,這個是java所沒有的。

import (    "io"

   "log"
   "net"

   "strconv")

類型轉換

go對於變量的類型有嚴格的限制,不同類型之間的變量不能進行賦值、表達式等操作,必須要要轉換成同一類型才可以,比如int32和int64兩種int類型的變量不能直接相加,要轉換成一樣才可以。

   var a int32 = 13
   var b int64 = 20

   c := int64(a) + b

這種限制主要是防止我們誤操作,導致一些莫名其妙的問題。在java中因為有自動轉型的概念,所以可以不同類型的可以進行操作,比如int可以和double相加,int類型可以通過+和字符串拼接起來,這些在go中都是不可行的。

map

map類型,Java裡是Map接口,go裡叫做字典,因為其常用,在go中,被優化為一個語言上支持的結構,原生支持,就像一個關鍵字一樣,而不是java裡的要使用內置的sdk集合庫,比如HashMap等。

   ages := make(map[string]int)

   ages["linday"] = 20
   ages["michael"] = 30

   fmt.Print(ages["michael"])

go裡要創建一個map對應,需要使用關鍵字make,然後就可以對這個map進行操作。

map的結構也非常簡單,符合KV模型,定義為map[key]value, 方括號裡是key的類型,方括號外緊跟著對應的value的類型,這些明顯和Java的Map接口不同。如果在go中我們要刪除map中的一個元素怎麼辦?使用內置的delete函數就可以,如下代碼刪除ages這個map中,key為michael的元素。

delete(ages,"michael")

如果我們想遍歷map中的KV值怎麼辦?答案是使用range風格的for循環,可比Java Map的遍歷簡潔多了。

   for name,age := range ages {
       fmt.Println("name:",name,",age:",age)
   }

range一個map,會返回兩個值,第一個是key,第二個是value,這個也是go多值返回的優勢,下面會講。

函數方法

在go中,函數和方法是不一樣的,我們一般稱包級別的(直接可以通過包調用的)稱之為函數,比如fmt.Println();把和一個類型關聯起來的函數稱之為方法,如下示例:

package libimport "time"type Person struct {

   age  int

   name string}func (p Person) GetName() string {    return p.name

}func GetTime() time.Time{    return time.Now()

}

其中GetTime()可以通過lib.GetTime()直接調用,稱之為函數;而GetName()則屬於Person這個結構體的函數,只能聲明了Person類型的實例後才可以調用,稱之為方法。

不管是函數還是方法,定義是一摸一樣的。而在這裡,最可以講的就是多值返回,也就是可以同時返回多個值,這就大大為我們帶來了方便,比如上個遍歷map的例子,直接可以獲取KV,如果只能返回一個值,我們就需要調用兩次方法才可以。

func GetTime() (time.Time,error){    return time.Now(),nil}

多值返回也很簡單,返回的值使用逗號隔開即可。如果要接受多值的返回,也需要以逗號分隔的變量,有幾個返回值,就需要幾個變量,比如這裡:

now,err:=GetTime()

如果有個返回值,我們用不到,不想浪費一個變量接收怎麼辦?這時候可以使用空標誌符_,這是java沒有的。

now,_:=GetTime()

指針

Go的指針和C中的聲明定義是一樣的,其作用類似於Java引用變量效果。

   var age int = 10
   var p *int = &age
   *p = 11
   fmt.Println(age)

其中指針p指向變量age的內存地址,如果修改*p的值,那麼變量age的值也同時會被修改,例子中列印出來的值為11,而不是10.

相對應java引用類型的變量,可以理解為一個HashMap類型的變量,這個變量傳遞給一個方法,在該方法裡對HashMap修改,刪除,就會影響原來的HashMap。引用變量集合類最容易理解,自己的類也可以,不過基本類型不行,基本類型不是引用類型的,他們在方法傳參的時候,是拷貝的值。

結構體替代類

Go中沒有類型的概念,只有結構體,這個和C是一樣的。

type Person struct {
   age  int
   name string}

Go中的結構體是不能定義方法的,只能是變量,這點和Java不一樣的,如果要訪問結構體內的成員變量,通過.操作符即可。

func (p Person) GetName() string {    return p.name

}

這就是通過.操作符訪問變量的方式,同時它也是一個為結構體定義方法的例子,和函數不一樣的是,在func關鍵字後要執行該方法的接收者,這個方法就是屬於這個接收者,例子中是Person這個結構體。

在Go中如果想像Java一樣,讓一個結構體繼承另外一個結構體怎麼辦?也有辦法,不過在Go中稱之為組合或者嵌入。

type Person struct {
   age  int
   name string
   Address

}type Address struct {

   city string}

結構體Address被嵌入了Person中,這樣Person就擁有了Address的變量和方法,就像自己的一樣,這就是組合的威力。通過這種方式,我們可以把簡單的對象組合成複雜的對象,並且他們之間沒有強約束關係,Go倡導的是組合,而不是繼承、多態。

接口

Go的接口和Java類型,不過它不需要強制實現,在Go中,如果你這個類型(基本類型,結構體等都可以)擁有了接口的所有方法,那麼就默認為這個類型實現了這個接口,是隱式的,不需要和java一樣,強制使用implement強制實現。

type Stringer interface {
   String() string}func (p Person) String() string {    return "name is "+p.name+",age is "+strconv.Itoa(p.age)
}

以上實例中可以看到,Person這個結構體擁有了fmt.Stringer接口的方法,那麼就說明Person實現了fmt.Stringer接口。

接口也可以像結構體一樣組合嵌套,這裡不再贅述。

並發

Go並發主要靠go goroutine支持,也稱之為go協程或者go程,他是語言層面支持的,非常輕量級的多任務支持,也可以把他簡單的理解為java語言的線程,不過是不一樣的。

go run()

這就啟動一個goroutine來執行run函數,代碼非常簡潔,如果在java中,需要先New一個Thread,然後在重寫他的run方法,然後在start才可以開始。

兩個goroutine可以通過channel來通信,channel是一個特殊的類型,也是go語言級別上的支持,他類似於一個管道,可以存儲信息,也可以從中讀取信息。

package mainimport "fmt"func main() {

   result:=make(chan int)    go func() {

       sum:=0
       for i:=0;i<10;i++{
           sum=sum+i
       }
       result<-sum
   }()
   fmt.Print(<-result)
}

以上示例使用一個單獨的goroutine求和,當得到結果時,存放在result這個chan裡,然後供main goroutine讀取出來。當result沒有被存儲值的時候,讀取result是阻塞的,所以會等到結果返回,協同工作,通過chan通信。

對於並發,go還提供了一套同步機制,都在sync包裡,有鎖,有一些常用的工具函數等,和java的concurrent框架差不多。

異常機制

相比java的Exception來說,go有兩種機制,不過最常用的還是error錯誤類型,panic只用於嚴重的錯誤。

type error interface {

   Error() string}

go內置的error類型非常簡潔,只用實現Error方法即可,可以列印一些詳細的錯誤信息,比如常見的函數多值返回,最後一個返回值經常是error,用於傳遞一些錯誤問題,這種方式要比java throw Exception的方法更優雅。

Defer代替finally

go中沒有java的finally了,那麼如果我們要關閉一些一些連接,文件流等怎麼辦呢,為此go為我們提供了defer關鍵字,這樣就可以保證永遠被執行到,也就不怕關閉不了連接了。

f,err:=os.Open(filename)defer f.Close()

readAll(f)

統一編碼風格

在編碼中,我們有時為了是否空行,大括號是否獨佔一行等編碼風格問題爭論不休,到了Go這裡就終止了,因為go是強制的,比如花括號不能獨佔一行,比如定義的變量必須使用,否則就不能編譯通過。

第二種就是go fmt這個工具提供的非強制性規範,雖然不是強制的,不過也建議使用,這樣整個團隊的代碼看著就像一個人寫的。很多go代碼編輯器都提供保存時自動gofmt格式的話,所以效率也非常高。

便捷的部署

go最終生成的是一個可執行文件,不管你的程序依賴多少庫,都會被打包進行,生成一個可執行文件,所以相比java龐大的jar庫來說,他的部署非常方便,執行運行這個可執行文件就好了。

對於Web開發,更方便,不用安裝jdk,tomcat容器等等這些環境,直接一個可執行文件,就啟動了。對於go這種便捷的部署方式,我覺得他更能推進docker的服務化,因為docker就是倡導一個實例一個服務,而且不用各種依賴,layer層級又沒那麼多,docker image也會小很多。

最後,go目前已經在TIOBE語言排行榜上名列13名了,上升速度還是非常快的,而且隨著服務化,容器化,他的優勢會越來越多的顯現出來,得到更廣泛的應用。

如果你感興趣,那麼開始吧,提前準備,機會來的時候,就不會錯過了。

推薦閱讀


喜歡本文的朋友,歡迎關注「Go語言中文網」:

相關焦點

  • java如何快速入門?
    java如何快速入門正確掌握Java的基本知識由於Java為開發人員提供了如此多的特性和選項,人們有時會被分散注意力在太短的時間內學習了太多的東西java如何快速入門真正弄懂你敲出的代碼是做什麼的只要你理解了代碼背後的思想,算法和整個編譯過程就會顯得非常有意義。
  • 軟帝學院:Java程式設計師入門必看的 4 本 Java 書籍!
    01《Head First Java》作為一本入門書,它是絕對出色的。一個星期就能讓你明白怎麼用Java寫程序了。尤其是你有其它語言基礎的情況下,這本書能迅速讓你明白Java的特質。 缺點是,它真的只是入門書。02《Java 核心技術:卷1 基礎知識》
  • java入門必備書籍
    共覆蓋了java.awt、java.lang、java.io和java.nio、java.sql、java.text、java.util、javax.swing包下絕大部分類和接口。只要你真正想學習Java,你翻開書看上十多分鐘,你絕對會被這本書吸引,介紹操作的部分,非常具體。2.Java2入門經典
  • Go 擺脫了 C,又惹上了 Java?
    (Go 1.4 已經正式支持 Android)4月份進行的 NYJavaSIG 聚會上 Go 團隊的技術主管經理分享了《Go for Java Programmers》,為 Java 程式設計師提供的 Go 入門指南,正式向 Java 領域進軍了嗎?
  • 為什麼都說java比較容易入門?
    說java比較容易入門的人,應該都是正常的人,因為相比之下,java有著不可比擬的優勢,對於編程新手來說這個優勢,可以讓他們更快的用
  • 程式設計師書單,你讀過幾本?
    做為二十一世紀缺少人才--Java工程師,你讀書破萬卷了嗎?為了滿足我們好讀書的程式設計師能讀好書的願望,小編不辭勞苦,找了"萬卷"關於java學習的書籍,希望每位猿猿都能讀一讀!1、java學習基礎編程篇Java程序設計語言.
  • 如何快速學習Java?
    【CSDN編者按】在各大程式語言學習榜單上,Java的入門難度不言而喻。除了要科學選擇一門適合自己的程式語言,還有沒有快速入門的方法呢?近期,我們整理了來自Quora上來自網友的回答,希望給予更多參考。回復一:1.
  • Java程式設計師憑什麼工資那麼高?
    首先,我們看一下有關調查統計的數據:相信大家都能看得出Java程式設計師的在這些行業中的工資待遇確實很高,引起大家羨慕不已,甚至很多人因為它的高收入而去轉行。那為什麼Java程式設計師的工資這麼高?接下來我們詳細分析一下。
  • 為什麼入門大數據選擇Python而不是Java?
    它常被暱稱為膠水語言,能夠把用其他語言製作的各種模塊(尤其是C/C++)很輕鬆地聯結在一起。7月20日,IEEE發布2017年程式語言排行榜:Python高居首位。java和python,都可以運行於linux作業系統,但很多linux可以原生支持python,java需要自行安裝。java和python強於c#的原因大於支持linux,支持osx,支持unix,支持arm。
  • Go 擺脫了 C,又惹上了 Java? - OSCHINA - 中文開源技術交流社區
    (Go 1.4 已經正式支持 Android)4月份進行的 NYJavaSIG 聚會上 Go 團隊的技術主管經理分享了《Go for Java Programmers》,為 Java 程式設計師提供的 Go 入門指南,正式向 Java 領域進軍了嗎?
  • 小白入門Java必備攻略!
    今天來為大家推薦一個快速入門Java的學習課程(親測有效!)如果你現在還在迷茫之中不知如何選擇一門適合自己學習的程式語言,那麼相信你看完以下內容可以做出選擇了。2020年初,突如其來的疫情讓很多行業受到了不小的衝擊,但同時也促使著某些行業正在快速的向前發展。我們也應當看到疫情對「網際網路+」產業的推動作用。
  • Java第一篇:Java程序入門
    入門Java程序編寫源程序在d:\day01 目錄下新建文本文件,完整的文件名修改為HelloWorld.java ,其中文件名為HelloWorld
  • 阿里Arthas工具在做Java應用診斷上真牛逼!入門教程趕緊學起來!
    由於公眾號文章推送規則的改變,大家能準時收到我們的文章推送,請將公眾號: JAVA程式語言 設為星標~這樣就不會錯過每一篇精彩的推送啦
  • 程式設計師學Java要關注的6個網站,你知道幾個呢?
    下面w3cschool給程式設計師小夥伴們分享java學習的6個網站:0、SourgeForgeSourgeForge是開源軟體開發者進行開發管理的集中式網站。有相當豐富的Java開放原始碼的著名的軟體。1、w3cschool網站有不少入門Java的程式設計師學了幾個月一頭霧水,抓不住一些重點、核心的編程知識點。還有一些程式設計師感覺到編程過於枯燥,靜不下心來學習。
  • 「核心基礎篇」Guide的Java後端書架來啦!都是Java程式設計師必看的書籍?
    JVMJVM 這裡就先只推薦一本書籍和一個關於 JVM 參數調優的免費教程(你假笨大佬的)。《深入理解 Java 虛擬機(第 3 版)》程式設計師必看!這本書我覺是每一個程式設計師都必須要看,並且需要看很多次的!《Effective java 》
  • Kotlin 喧囂過後,談談 Java 程式設計師未來的出路
    Spring BootSpring Boot 是 Pivotal 團隊推出的一個支持快速開發的框架,伴隨 Spring4.0 而生,繼承了 Spring 的優秀特質,簡化了使用 Spring 編碼、配置、部署的過程,使項目的開發變得簡單、敏捷。
  • Java四大名著是什麼?java程式設計師提高技能的經典編程書籍推薦
    高薪程式設計師必讀的幾本書,基礎編程書籍推薦》,下面,再針對java程式設計師,梳理一些常見的圖書,期望對正在使用java編程的小夥伴有參考。學任何語言,基本的語法知識不能少,首推,Java四大名著( java編程思想+Effective java中文版+Java核心技術卷12),下面來具體介紹以下包含Java四大名著在內的java程式設計師類圖書。
  • Go語言和Java、Python等其他語言的對比分析
    2、效率:快速的編譯時間,開發效率和運行效率高開發過程中相較於 Java 和 C++呆滯的編譯速度,Go 的快速編譯時間是一個主要的效率優勢。Go擁有接近C的運行效率和接近PHP的開發效率。C 語言的理念是信任程式設計師,保持語言的小巧,不屏蔽底層且底層友好,關注語言的執行效率和性能。
  • 作為一個Java 程式設計師 你應該會什麼
    一,JAVA架構師1、語法:Java 程式設計師必須比較熟悉語法,在寫代碼的時候IDE 的編輯器對某一行報錯應該能夠根據報錯信息 知道是什麼樣的語法錯誤並且知道任何修正。4、API:Java 的核心API 是非常龐大的,但是有一些內容筆者認為是Java程式設計師必須熟悉的,否則不可能熟練的運用Java,包括:◆java.lang 包下的80%以上的類的功能的靈活運用。
  • 為什麼很多java程式設計師都不喜歡PHP程式設計師?
    為什麼很多java程式設計師都不喜歡PHP程式設計師?這不是引戰的標題,小編是根據身邊很多程式設計師講述,特別是比較喜歡java程式設計師而總結出來的。在工作中,很多公司隨著業務的增加與需求多樣性,有些企業就是要求用PHP開發,所以很多開發公司都是跟著市場走,主流的程式語言java與PHP碰面,多數情況下java程式設計師都不喜歡PHP程式設計師。