go語言最主要的特性
go語言最主要特性主要是:
自動垃圾回收
更豐富的內建型別函式多返回值
錯誤處理
匿名函式和閉包
型別和介面
併發程式設計
反射
語言互動性
1、自動垃圾回收
能夠像java、C#等語言自帶GC,不用再為記憶體管理苦惱
2、更豐富的內建型別
關鍵在於內建,像map、slice這些常用的資料型別,內置於builtin,預設包含,無需自己新增。
3、函式返回多值
多值返回僅動態語言Python有此特性
func getName()(firstName, middleName, lastName, nickName string){
return "May", "M", "Chen", "Babe"
}
func getName()(firstName, middleName, lastName, nickName string){
firstName = "May"
middleName = "M"
lastName = "Chen"
nickName = "Babe"
return
}
_, _, lastName, _ := getName()
4、錯誤處理
3個重要關鍵字defer、panic、recover
defer是函式結束後執行,呈先進後出;
panic是程式出現無法修復的錯誤時使用,但會讓defer執行完;
recover會修復錯誤,不至於程式終止。當不確定函式不會出錯時使用defer+recover
packagemain
import(
"log"
)
funcfixError(){
ifr:=recover();r!=nil{
log.Printf("errcaught:%v",r)
}else{
log.Println("noerr")
}
}
funcmyDivide(x,yint)int{
returnx/y
}
functestFunc(){
deferfixError()
myDivide(6,0)
}
funcmain(){
testFunc()
log.Println("mainend")
}
/Users/zhaojunyan/go/src/src [/Users/zhaojunyan/go/src]
2018/01/29 12:52:44 err caught: runtime error: integer divide by zero
2018/01/29 12:52:44 main end
成功: 程序退出程式碼 0.
5、匿名函式和閉包
匿名函式就是一個沒有名字的函式,本身也是一個閉包
funcmain(){
f:=func(x,yint)int{
returnx+y
}
fmt.Println(f(4,5))
z:=func(x,yint)int{
fmt.Println("匿名函式,直接執行","x:",x,"y:",y)
returnx+y
}(6,7)
fmt.Println(z)
}
閉包是可以包含自由變數的程式碼塊,這些變數不在這個程式碼塊內或者任何全域性上下文中定義,而是在定義程式碼塊的環境中定義。
閉包的價值在於可以作為函式物件或者匿名函式,儲存到變數中作為引數傳遞給其他函式,能夠被函式動態建立和返回。packagemain
import(
"fmt"
)
funcmain(){
varjint=5
a:=func()func(){
variint=10
returnfunc(){
fmt.Printf("i,j:%d,%d\n",i,j)
}
}()
a()
j*=2
a()
}
/Users/zhaojunyan/go/src/src [/Users/zhaojunyan/go/src]
i, j: 10, 5
i, j: 10, 10
成功: 程序退出程式碼 0.
再看個複雜的:
packagemain
import"fmt"
funcadder()func(int)int{
sum:=0
returnfunc(xint)int{
sum+=x
returnsum
}
}
funcmain(){
pos:=adder()
n:=10
fmt.Println(pos(n))
}
此時,n是多少,打印出來的就是多少,但是當pos(n)多執行幾次,就會發現不同。
funcmain(){
pos:=adder()
n:=10
fmt.Println(pos(n))
fmt.Println(pos(n))
fmt.Println(pos(n))
}
/Users/zhaojunyan/go/src/src [/Users/zhaojunyan/go/src]
10
20
30
成功: 程序退出程式碼 0.
發現結果,成n的倍數增長。其實pos的函式體雖然是sum:=0
returnfunc(xint)int{
sum+=x
returnsum
}
但是sum是一個閉包變數,或者理解為僅初始化一次,且是一個靜態變數。備註:return之前的程式碼僅執行一次。
如下面示例程式碼,sum:=0和sum=9都僅執行一次:
packagemain
import"fmt"
funcadder()func(int)int{
sum:=0
sum=9
returnfunc(xint)int{
sum+=x
returnsum
}
}
funcmain(){
pos:=adder()
n:=10
fmt.Println(pos(n))
fmt.Println(pos(n))
fmt.Println(pos(n))
}
/Users/zhaojunyan/go/src/src [/Users/zhaojunyan/go/src]
19
29
39
成功: 程序退出程式碼 0.
6、型別和介面
型別非常接近於C語言中的結構體,也使用了struct。go語言型別不支援繼承和過載,僅有封裝和組合。
go語言引入了強大的“非侵入式”介面,無需指明型別實現了哪個介面。
7、併發程式設計
go語言倡導使用訊息傳遞來共享記憶體,引入了goroutine概念,這是一個協程,更輕量級的執行緒。與channel搭配使用。
packagemain
import"fmt"
funcsum(values[]int,resultChanchanint){
sum:=0
for_,value:=rangevalues{
sum+=value
}
resultChan<-sum//將計算結果傳送到channel中
}
funcmain(){
values:=[]int{1,2,3,4,5,6,7,8,9,10}
resultChan:=make(chanint,2)
gosum(values[:len(values)/2],resultChan)
gosum(values[len(values)/2:],resultChan)
sum1,sum2:=<-resultChan,<-resultChan//接收結果
fmt.Println("Result:",sum1,sum2,sum1+sum2)
}
8、反射
通過反射,你可以獲取物件型別的詳細資訊,並可動態操作物件。反射是把雙刃劍,功能強大但程式碼可讀性並不理想。若非必要,不推薦使用反射。
packagemain
import(
"fmt"
"reflect"
)
typeBirdstruct{
Namestring
LifeExpectanceint
}
func(b*Bird)Fly(){
fmt.Println("Iamflying...")
}
funcmain(){
sparrow:=&Bird{"Sparrow",3}
s:=reflect.ValueOf(sparrow).Elem()
typeOfT:=s.Type()
fori:=0;i<s.NumField();i++{
f:=s.Field(i)
fmt.Printf("%d:%s%s=%v\n",i,typeOfT.Field(i).Name,f.Type(),
f.Interface())
}
}
/Users/zhaojunyan/go/src/src [/Users/zhaojunyan/go/src]
0: Name string = Sparrow
1: LifeExpectance int = 3
成功: 程序退出程式碼 0.
9、語言互動性
由於Go語言與C語言之間的天生聯絡,Go語言的設計者們自然不會忽略如何重用現有C模組 的這個問題,這個功能直接被命名為Cgo。Cgo既是語言特性,同時也是一個工具的名稱。
packagemain
//#include<stdio.h>
import"C"
funcmain(){
cstr:=C.CString("ab,Hello,world")
C.puts(cstr)
println(*cstr)
}