寫在前面:
近來關(guān)于對(duì)Golang的討論有很多,7牛的幾個(gè)大牛們也判定Go語(yǔ)言在未來將會(huì)快速發(fā)展,并且極可能會(huì)取代Java成為互聯(lián)網(wǎng)時(shí)期最受歡迎的編程語(yǔ)言。Go語(yǔ)言是google推出的編程語(yǔ)言,在已成功的給眾人創(chuàng)造了改變?nèi)藗兩畹牟僮飨到y(tǒng)以后,google仿佛感覺有必要再為眾人帶來1款強(qiáng)大的編程語(yǔ)言,而Go語(yǔ)言依托自己眾多友好的特性也不負(fù)眾望正在被開發(fā)者接觸,我有幸在學(xué)習(xí)高性能并發(fā)編程的時(shí)候認(rèn)識(shí)了Go語(yǔ)言,在了解了Go的1些特性以后決定系統(tǒng)的學(xué)習(xí)1番。我發(fā)現(xiàn)關(guān)于Go的學(xué)習(xí)資料其實(shí)不多,以致于我需要自己寫1些東西。這里的內(nèi)容大多來自7牛團(tuán)隊(duì)的《Go語(yǔ)言編程》1書。這里也會(huì)依照書中組織的章節(jié)進(jìn)行學(xué)習(xí)。固然如果1些知識(shí)點(diǎn)事互聯(lián)網(wǎng)上已有的,這里直接進(jìn)行轉(zhuǎn)載了。
-Written by Lingtao in Nanjing.
依照書中說的,Go語(yǔ)言具有以下的特點(diǎn),下面我們分別來進(jìn)行介紹。
? 自動(dòng)垃圾回收
? 更豐富的內(nèi)置類型
? 函數(shù)多返回值
? 毛病處理
? 匿名函數(shù)和閉包
? 類型和接口
? 并發(fā)編程
? 反射
? 語(yǔ)言交互性
從C到C++,從程序性能的角度來斟酌,這兩種語(yǔ)言允許程序員自己管理內(nèi)存,包括內(nèi)存的申請(qǐng)和釋放等。由于沒有垃圾回收機(jī)制所以C/C++運(yùn)行起來速度很快,但是隨著而來的是程序員對(duì)內(nèi)存使用上的很謹(jǐn)小慎微的斟酌。由于哪怕1點(diǎn)不謹(jǐn)慎便可能會(huì)致使“內(nèi)存泄漏”使得資源浪費(fèi)或“野指針”使得程序崩潰等,雖然C++11后來使用了智能指針的概念,但是程序員依然需要很謹(jǐn)慎的使用。后來為了提高程序開發(fā)的速度和程序的硬朗性,java和C#等高級(jí)語(yǔ)言引入了GC機(jī)制,即程序員不需要再斟酌內(nèi)存的回收等,而是由語(yǔ)言特性提供垃圾回收器來回收內(nèi)存。但是隨之而來的多是程序運(yùn)行效力的下降。
“Go語(yǔ)言作為1門新生的開發(fā)語(yǔ)言,固然不能疏忽內(nèi)存管理這個(gè)問題。又由于Go語(yǔ)言沒有C++
這么“強(qiáng)大”的指針計(jì)算功能,因此可以很自然地包括垃圾回收功能。由于垃圾回收功能的支持,開發(fā)者無需擔(dān)心所指向的對(duì)象失效的問題,因此Go語(yǔ)言中不需要delete關(guān)鍵字,也不需要free()方法來明確釋放內(nèi)存”.
其實(shí)作為1種新興的語(yǔ)言,如果僅僅是為了某種特定的用處那末可能其內(nèi)置類型不是很多,僅需要能夠完成我的功能便可,但是Go語(yǔ)言“不但支持幾近所有語(yǔ)言都支持的簡(jiǎn)單內(nèi)置類型(比如整型和浮點(diǎn)型等)外,還支持1些其他的高級(jí)類型,比如字典類型,map要知道這些類型在其他語(yǔ)言中都是通過包的情勢(shì)引入的外部數(shù)據(jù)類型。數(shù)組切片(Slice),類似于C++ STL中的vector,在Go也是1種內(nèi)置的數(shù)據(jù)類型作為動(dòng)態(tài)數(shù)組來使用。這里滿有1個(gè)很是簡(jiǎn)單的解釋:”既然絕大多數(shù)開發(fā)者都需要用到這個(gè)類型,為何還非要每一個(gè)人都寫1行import語(yǔ)句來包括1個(gè)庫(kù)?”
在C,C++中,包括其他的1些高級(jí)語(yǔ)言是不支持多個(gè)函數(shù)返回值的。但是這項(xiàng)功能又確切是需要的,所以在C語(yǔ)言中1般通過將返回值定義成1個(gè)結(jié)構(gòu)體,或通過函數(shù)的參數(shù)援用的情勢(shì)進(jìn)行返回。而在Go語(yǔ)言中,作為1種新型的語(yǔ)言,目標(biāo)定位為強(qiáng)大的語(yǔ)言固然不能放棄對(duì)這1需求的滿足,所以支持函數(shù)多返回值是必須的,例如:
> func getName()(firstName, middleName, lastName, nickName string){
> return "May", "M", "Chen", "Babe" } //定義了1個(gè)多返回值的函數(shù)getName
>
> fn, mn, ln, nn := getName() //調(diào)用賦值
> _, _, lastName, _ := getName() //缺省調(diào)用
在傳統(tǒng)的OOP編程中,為了捕獲程序的硬朗性需要捕獲異常,使用的方法大都是try() catch{}模塊,例如, 在下面的java代碼中,可能需要的操作是:
Connection conn = ...;
try {
Statement stmt = ...;
...//別的1些異常捕獲
finally {
stmt.close();
}
finally {
conn.close();
}
而在Go中引入了3個(gè)關(guān)鍵字,分別是 defer、panic和recover,其中使用defer關(guān)鍵字語(yǔ)句的含義是不管程序是不是出現(xiàn)異常,均在函數(shù)退出時(shí)自動(dòng)履行相干代碼。
所以上面你的java代碼用Go進(jìn)程重寫只有兩行:
conn := ...
defer conn.Close()
另外兩個(gè)關(guān)鍵詞后面再討論。所以“Go語(yǔ)言的毛病處理機(jī)制可以大量減少代碼量,讓開發(fā)者也無需僅僅為了程序安全性而添加大量1層套1層的try-catch語(yǔ)句。這對(duì)代碼的瀏覽者和保護(hù)者來講也是1件很好的事情,由于可以免在層層的代碼嵌套中定位業(yè)務(wù)代碼。”
關(guān)于這個(gè)功能介紹的不多,大概就是說Go中的函數(shù)也能夠作為參數(shù)進(jìn)行傳遞:
“在Go語(yǔ)言中,所有的函數(shù)也是值類型,可以作為參數(shù)傳遞。Go語(yǔ)言支持常規(guī)的匿名函數(shù)和閉包,比以下列代碼就定義了1個(gè)名為f的匿名函數(shù),開發(fā)者可以隨便對(duì)該匿名函數(shù)變量進(jìn)行傳遞和調(diào)用:
f := func(x, y int) int {
return x + y
}
”
這個(gè)特性是Go在實(shí)現(xiàn)OPP時(shí)候的1些特性,主要有這么幾點(diǎn):
第1: Go語(yǔ)言沒有很復(fù)雜的面向?qū)ο蟮母拍睿礇]有繼承和重載,其類型更像是C中的struct,并且直接使用了struct關(guān)鍵字,僅僅是最基本的類型組合功能。但是,雖然不支持這些語(yǔ)法特性,但是Go的OOP卻一樣可以實(shí)現(xiàn)這些功能,只是實(shí)現(xiàn)的情勢(shì)上會(huì)有不同而已。
即這里需要介紹的“非侵入型”接口的概念。
舉個(gè)例子:
在C++中,1般會(huì)這樣定義1個(gè)接口和類型的
// 抽象接口
interface IFly
{
virtual void Fly()=0;
};
// 實(shí)現(xiàn)類
class Bird : public IFly
{
public:
Bird() {}
virtual ~Bird() {}
void Fly()
{
// 以鳥的方式飛行
}
};
//使用的時(shí)候
void main()
{
IFly* pFly = new Bird();
pFly->Fly();
delete pFly;
}需要你自己以虛函數(shù)的情勢(shì)定義1個(gè)接口,并且讓類型繼承這個(gè)接口并重寫虛方法。在使用的時(shí)候需要進(jìn)行動(dòng)態(tài)綁定。
而在Go中實(shí)現(xiàn)相同的功能,你只需要
type Bird struct {
…
}
func (b *Bird) Fly() {
// 以鳥的方式飛行
}
type IFly interface {
Fly()
}
func main() {
var fly IFly = new(Bird)
fly.Fly()
}
可以看出,“雖然Bird類型實(shí)現(xiàn)的時(shí)候,沒有聲明與接口IFly的關(guān)系,但接口和類型可以直
接轉(zhuǎn)換,乃至接口的定義都不用在類型定義之前,這類比較疏松的對(duì)應(yīng)關(guān)系可以大幅下降由于接
口調(diào)劑而致使的大量代碼調(diào)劑工作”。
其實(shí)到目前為止,最吸引我的就是這個(gè)特性,而且我之前說了如果不是由于要做服務(wù)器的高并發(fā)我可能根本就不知道Go這類語(yǔ)言,在上1篇文章http://blog.csdn.net/michael_kong_nju/article/details/45420047 中討論了為何Go可以實(shí)現(xiàn)大范圍的并發(fā)的原理,這里不做詳細(xì)的介紹,只給出實(shí)現(xiàn)方法,即
“Go語(yǔ)言引入了goroutine概念,它使得并發(fā)編程變得非常簡(jiǎn)單。通過使用goroutine而不是裸用操作系統(tǒng)的并發(fā)機(jī)制,和使用消息傳遞來同享內(nèi)存而不是使用同享內(nèi)存來通訊,Go語(yǔ)言讓并發(fā)編程變得更加輕盈和安全。通過在函數(shù)調(diào)用前使用關(guān)鍵字go,我們便可讓該函數(shù)以goroutine方式履行,goroutine是1種比線程更加輕盈、更省資源的協(xié)程。”
“同時(shí),Go語(yǔ)言實(shí)現(xiàn)了CSP(通訊順序進(jìn)程,Communicating Sequential Process)模型來作為goroutine間的推薦通訊方式,在CSP模型中,1個(gè)并發(fā)系統(tǒng)由若干并行運(yùn)行的順序進(jìn)程組成,每一個(gè)進(jìn)程不能對(duì)其他進(jìn)程的變量賦值。進(jìn)程之間只能通過1對(duì)通訊原語(yǔ)實(shí)現(xiàn)協(xié)作。Go語(yǔ)言用channel(通道)這個(gè)概念來輕巧地實(shí)現(xiàn)了CSP模型。channel的使用方式比較接近Unix系統(tǒng)中的管道(pipe)概念,可以方便地進(jìn)行跨goroutine的通訊。”
“另外,另外,由于1個(gè)進(jìn)程內(nèi)創(chuàng)建的所有g(shù)oroutine運(yùn)行在同1個(gè)內(nèi)存地址空間中,因此如果不同的goroutine不能不去訪問同享的內(nèi)存變量,訪問前應(yīng)當(dāng)先獲得相應(yīng)的讀寫鎖。Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)中的sync包提供了完備的讀寫鎖功能。”
這里的反射(reflecttion)和JAVA中的反射類似,可以用來獲得對(duì)象類型的相信信息,并動(dòng)態(tài)操作對(duì)象。由于反射可能會(huì)對(duì)程序的可讀性有很大的干擾,所以,在Go中只是在特別需要反射支持的地方才實(shí)現(xiàn)反射的1些功能。“反射最多見的使用處景是做對(duì)象的序列化(serialization,有時(shí)候也叫Marshal & Unmarshal)。例如,Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)的encoding/json、encoding/xml、encoding/gob、encoding/binary等包就大量依賴于反射功能來實(shí)現(xiàn)。”
這里的交互性主要是和C的交互性,之所以這樣是由于Go語(yǔ)言的開發(fā)者是最初貝爾實(shí)驗(yàn)室創(chuàng)建Unix系統(tǒng)和C語(yǔ)言的1般人,包括:
肯?湯普遜(Ken Thompson,http://en.wikipedia.org/wiki/Ken_Thompson):設(shè)計(jì)了B語(yǔ)言和C語(yǔ)言,創(chuàng)建了Unix和Plan 9操作系統(tǒng),1983年圖靈獎(jiǎng)得主,Go語(yǔ)言的共同作者。
在Go語(yǔ)言中直接重用了大部分的C模塊,這里稱為Cgo.Cgo允許開發(fā)者混合編寫C語(yǔ)言代碼,然后Cgo工具可以將這些混合的C代碼提取并生成對(duì)C功能的調(diào)用包裝代碼。開發(fā)者基本上可以完全疏忽這個(gè)Go語(yǔ)言和C語(yǔ)言的邊界是如何逾越的。
例如書中1個(gè)例子,在Go語(yǔ)言中直接調(diào)用了C標(biāo)準(zhǔn)庫(kù)的puts函數(shù)。
package main
/*
#include <stdio.h>
*/
import "C"
import "unsafe"
func main() {
cstr := C.CString("Hello, world")
C.puts(cstr)
C.free(unsafe.Pointer(cstr))
}
以上就是書中總結(jié)的Go語(yǔ)言的9大特性,這里面我看完以后根據(jù)自己的體會(huì)和書中的1些總結(jié)進(jìn)行了匯總。對(duì)想了解Go這么語(yǔ)言,和準(zhǔn)備進(jìn)入這個(gè)領(lǐng)域的人可以對(duì)Go有1個(gè)大概的認(rèn)識(shí)。如果想深入的學(xué)習(xí)可以去看7牛云存儲(chǔ)團(tuán)隊(duì)出的《Go語(yǔ)言編程》。我后面也會(huì)繼續(xù)學(xué)習(xí)。