1. 程式人生 > >go語言最主要的特性

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{
return
x/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)
}