Golang 學習之路(三)函式

2021-09-24 19:38:48 字數 4447 閱讀 5934

函式可以為我們隱藏某乙個分解的任務的細節實現,暴露出需要的引數和返回結果。

在 go 語言中,如果一組形參或者返回值有相同的型別,我們不必為每個形參都寫出引數型別。

func

f(i int

, j int

, k int

, s string

, t string)==

=> 等價於

func

f(i, j, k int

, s, t string

)

在函式體中,函式的形參作為區域性變數,被初始化為呼叫者提供的值。函式的形參和有名返回值作為函式最外層的區域性變數,被儲存在相同的詞法塊中。

//go函式的返回值變數能被提前宣告,並且作用於整個函式的區塊內

func

f(x,y int

)(z int

,a string

)fmt.

println(f

(1,1

))//2 ok

實參通過值的方式傳遞,因此函式的形參是實參的拷貝。對形參進行修改不會影響實參。但是,如果實參包括引用型別,如指標,slicemapfunctionchannel等型別,實參可能會由於函式的間接引用被修改。

在go中,函式像其他值一樣,擁有型別,可以被賦值給其他變數,傳遞給函式,從函式返回。對函式值的呼叫類似函式呼叫一樣,函式可以賦值給乙個變數,然後通過變數來實現

func

square

(n int

)int

func

show

(m,n int

)int

f1 := square

fmt.

printf

("%t\n"

,f1)

//func(int) int

fmt.

println(f1

(2))

//4f2 := show

fmt.

printf

("%t\n"

,f2)

//func(int, int) int

fmt.

println(f2

(3,12

))//15

函式值可以減少重複**的使用,增加復用

package part1

//獲取url網頁內容的函式

func

fetchurl

(urls [

]string

)(s string

)byte

, err := ioutil.

readall

(resp.body)

resp.body.

close()

if err !=

nil s +=

string

(byte)}

return

}

var depth int

func

startelement

(n *html.node)

}func

endelement

(n *html.node)

}//遍歷節點之前,通過前置和後置函式處理新增空格

//pre函式和end函式都是可選的,並且作為引數傳遞

func

foreachelement

(n *html.node,pre,end func

(n *html.node)

)for c := n.firstchild;c !=

nil;c = c.nextsibling

if end !=

nil}

func

testforeachelement

(t *testing.t)

s := part1.

fetchurl

(url)

doc, err := html.

parse

(strings.

newreader

(s))

if err !=

nil//這裡直接傳入startelement和endelement函式作為引數

foreachelement

(doc,startelement,endelement)

}

擁有函式名的函式只能在包級語法塊中被宣告,通過函式字面量,我們可繞過這一限制,在任何表示式中表示乙個函式值。函式字面量的語法和函式宣告相似,區別在於func關鍵字後沒有函式名。函式值字面量是一種表示式,它的值被稱為匿名函式。

把上面的square函式來改寫下

func

square()

func()

int}

沒有名稱的函式func() int作為函式square的返回值,然後該匿名函式每次被呼叫的時候都會返回下乙個數的平方,每次呼叫匿名函式時,該函式都會先使x的值加 1 ,再返回x的平方。第二次呼叫square時,會生成第二個x變數,並返回乙個新的匿名函式。新匿名函式操作的是第二個x變數。

//測試呼叫square函式

func

testtwo

(t *testing.t)

在連續呼叫函式f3之後,列印的值表明在匿名函式中x遞增的,函式square和匿名函式之間存在著變數引用,函式值可以記錄狀態。也可以理解為為什麼函式值是引用型別並且函式值無法比較。go 使用閉包技術實現函式值,函式值也叫做閉包。

通過這個例子,我們看到變數的生命週期不由它的作用域決定:square返回後,變數x仍然隱式的存在於f中。

defer後面的函式總是會在包含defer的外圍函式執行完畢後才會執行,也就是說延時執行,不論包含defer語句的函式是通過return正常結束,還是由於panic導致的異常結束。你可以在乙個函式中執行多條defer語句,它們的執行順序與宣告順序相反。

func

testdeferred1

(t *testing.t)()

a, b =10,

20 fmt.

printf

("----->%d\t%d\n"

, a, b)

}//輸出:

----

->

1020

1020

300

可以看到,一開始並沒有按照順序執行defer後面匿名函式的內容,而是執行了後面的賦值a, b = 10, 20操作和列印,並且後續匿名函式的a,b的值也不是初始化的 1 和 2,而是 10 和 20。

在匿名函式傳參之後

func

testdeferred2

(t *testing.t)

(a, b)

a, b =10,

20 fmt.

printf

("----->%d\t%d\n"

, a, b)

}//輸出

----

->

102012

30

在將引數傳入到匿名函式之後,匿名函式保留著傳入之前的值,不再受到延遲執行之前其他的變數賦值操作,等價於下面的:

func

testdeferred3

(t *testing.t)

func

sh(a, b int

)//輸出

----

->

102012

30

defer語句經常被用於處理類似開始-關閉的操作,如開啟、關閉、連線、斷開連線、加鎖、釋放鎖。通過defer機制,不論函式邏輯多複雜,都能保證在任何執行路徑下,資源被釋放。釋放資源的defer應該直接跟在請求資源的語句後。

Golang學習之路 01

1 在go的結構體中,如果成員屬性小寫開頭代表這個成員是私有的,如果是大寫開頭代表是公開的。因此在定義一些json資料的結構體時,需要將成員屬性均改為大寫,否則無法解析 2 beego建立乙個純api專案,通過bee api 為專案名 建立以後我們需要進入專案目錄直接執行bee run gendoc...

golang學習三 函式, 記憶體, 工程管理

二 記憶體 三 函式 4.遞迴函式 四 工程管理 函式定義 func 函式名 引數1 型別,引數2 型別,函式呼叫 函式名 引數1 引數2 函式定義 func 函式名 args.int 語法 func 函式名 引數列表 引數型別 返回值型別 var res 引數型別 res 函式名 引數列表 示例 ...

golang學習之路 21切片copy

package main import fmt func main slice2 int copy slice2,slice1 fmt.println slice1,slice2 copy slice1,slice2 只會複製slice2的元素到slice1中,並且從第一位開始插入 fmt.prin...