函數(shù)function
成都創(chuàng)新互聯(lián)公司公司2013年成立,先為華坪等服務(wù)建站,華坪等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢(xún)服務(wù)。為華坪企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。- Go函數(shù)不支持 嵌套、重載和默認(rèn)參數(shù)
- 但支持以下特性:
無(wú)需聲明原形、不定長(zhǎng)變參、多返回值、命令返回值參數(shù)、匿名函數(shù)、閉包
- 定義函數(shù)使用關(guān)鍵字func,且大括號(hào)不能另起一行(所有有大括號(hào)的均遵循此原則)
- 函數(shù)也可以作為一種類(lèi)型的使用,直接賦值給變量(匿名函數(shù))
定義一個(gè)函數(shù)
格式:func name( 傳入的變量1 類(lèi)型,變量2 類(lèi)型 ) [ 返回變量 類(lèi)型,變量 類(lèi)型 ]{ }
- 傳入的變量可以沒(méi)有,也可以使多個(gè)
- 當(dāng)傳入的變量類(lèi)型相同時(shí),可以全部省略只留最后一個(gè)
func a(a,b,c int) {}
- 返回值可以有多個(gè),返回值類(lèi)型相同,也可以只留最后一個(gè),其中返回變量名稱(chēng)可以省略,省略的話(huà),就需要每返回一個(gè)寫(xiě)一個(gè)變量的類(lèi)型了,如果指定了返回某個(gè)局部變量,那么這個(gè)變量就已經(jīng)被定義,那么在函數(shù)體內(nèi)即可直接使用。
- 不指定返回變量名稱(chēng),那么需要在函數(shù)尾部寫(xiě)入 return 變量1,變量2, 如果指定了返回的變量名,那么只需要寫(xiě)上return即可。
- 傳入的參數(shù)個(gè)數(shù),也可以不定(不定長(zhǎng)變參),使用...來(lái)表示,在函數(shù)體內(nèi)存儲(chǔ)這些數(shù)據(jù)的類(lèi)型為slice
func A(a ...int) -->...int必須放在最后
- 如果傳入的值有1個(gè)string,有n個(gè)int,那么只能 fun A(b string, a ...int)這種形式接受
- 如果傳入的參數(shù)是一個(gè)常規(guī)的int、string等類(lèi)型的話(huà),屬于值傳遞(默認(rèn)),即只是值得拷貝,而如果傳遞sllice,則是引用傳遞(其實(shí)slice也屬于值拷貝,只不過(guò),slice拷貝的是內(nèi)存地址。而直接修改內(nèi)存地址會(huì)影響源數(shù)據(jù))
- 如果需要把int、string類(lèi)型的值傳入并修改,那么就需要把這些類(lèi)型的變量的內(nèi)存地址傳入
package main import "fmt" func main() { a := 2 A(a) fmt.Println(a) } func A(a int) { i := 3 fmt.Println(i) } 結(jié)果: 3 2
把變量a的地址傳入到函數(shù)中
package main import "fmt" func main() { a := 2 A(&a) //&a表示取a的內(nèi)存地址 fmt.Println(a) } func A(a *int) { //定義指針類(lèi)型,指向a的內(nèi)存地址 *a = 3 //直接對(duì)內(nèi)存地址進(jìn)行賦值 fmt.Println(*a) } 結(jié)果: 3 3
參數(shù)傳遞(傳值與傳指針)
函數(shù)的參數(shù)傳遞分為兩種,值傳遞,和引用傳遞,值傳遞指在調(diào)用函數(shù)時(shí)將實(shí)際參數(shù)復(fù)制一份傳遞到函數(shù)中,這樣在函數(shù)中如果對(duì)參數(shù)進(jìn)行修改,將不會(huì)影響到實(shí)際參數(shù)。默認(rèn)情況下,GO是值傳遞,在調(diào)用過(guò)程中不會(huì)影響到實(shí)際參數(shù)。
變量在內(nèi)存中是存放于一定的地址上的,修改變量實(shí)際是修改變量地址處的內(nèi)存。只有讓局部函數(shù)知道參數(shù)的內(nèi)存地址,才能修改變量的值。所以引用傳遞的時(shí)候需要把變量的內(nèi)存地址傳入到局部函數(shù)內(nèi)(&a,&表示傳遞變量的內(nèi)存地址),并將函數(shù)的參數(shù)類(lèi)型調(diào)整為*int,即改為指針類(lèi)型,才能在函數(shù)中修改變量的值,此時(shí)參數(shù)仍然是copy傳遞的,只不過(guò)copy的是一個(gè)指針。
函數(shù)作為其他變量的值
在Go語(yǔ)言中,一切皆類(lèi)型,函數(shù)也可以被命名為變量,然后對(duì)變量進(jìn)行函數(shù)的調(diào)用
package main import "fmt" func main() { a := A a() } func A() { fmt.Println("Func A") } 結(jié)果: Func A
匿名函數(shù)
在定義函數(shù)的時(shí)候不指定函數(shù)的名稱(chēng),而是把函數(shù)直接賦值給某個(gè)變量的函數(shù)叫做匿名函數(shù),調(diào)用這個(gè)函數(shù)的時(shí)候,直接使用變量的名稱(chēng)即可。(因?yàn)間olang中的func不支持函數(shù)嵌套,使用匿名函數(shù)可以達(dá)到嵌套的效果) 匿名函數(shù)不能作為頂級(jí)函數(shù)(最外層)
package main import "fmt" func main() { a := func() { fmt.Println("Func") } a() }
閉包函數(shù)
所謂閉包函數(shù)就是將整個(gè)函數(shù)的定義一氣呵成寫(xiě)好并賦值給一個(gè)變量。然后用這個(gè)變量名作為函數(shù)名去調(diào)用函數(shù)體。閉包函數(shù)對(duì)它外層的函數(shù)中的變量具有訪(fǎng)問(wèn)和修改的權(quán)限
package main import "fmt" func main() { f := closure(10) //調(diào)用閉包函數(shù)并傳遞10 fmt.Println(f(1)) //傳遞1給返回的函數(shù),10+1=11 fmt.Println(f(2)) //傳遞2給返回的函數(shù),10+2=12 } func closure(x int) func(int) int { //定義一個(gè)函數(shù)接收一個(gè)參數(shù)x,返回值也是一個(gè)函數(shù)接收一個(gè)變量y return func(y int) int { //返回一個(gè)int,函數(shù)接收一個(gè)參數(shù),返回x+y的值 return x + y } } 結(jié)果: 11 12
defer
- 執(zhí)行方式類(lèi)似其他語(yǔ)言中的析構(gòu)函數(shù),在函數(shù)體執(zhí)行結(jié)束后按照調(diào)用順序的相反順序逐個(gè)執(zhí)行 (類(lèi)似于棧的方式,先進(jìn)后出,后進(jìn)先出)
- 即使函數(shù)發(fā)生了嚴(yán)重錯(cuò)誤也會(huì)執(zhí)行
- 支持匿名函數(shù)的調(diào)用
- 常用語(yǔ)資源清理、文件關(guān)閉、解鎖以及記錄時(shí)間等操作
- 通過(guò)與匿名函數(shù)配合可在return之后修改函數(shù)計(jì)算結(jié)果
- 如果函數(shù)體內(nèi)某個(gè)變量作為defer時(shí)匿名函數(shù)的參數(shù),則在定義defer時(shí)已經(jīng)獲得了拷貝,否則則是引用某個(gè)變量的地址
- Go沒(méi)有異常機(jī)制,但有panic/recover模式來(lái)處理錯(cuò)誤
- Panic可以再任何地方引發(fā),但recover只有在defer調(diào)用的函數(shù)中有效
例子
package main import "fmt" func main() { fmt.Println("a") defer fmt.Println("1") defer fmt.Println("2") defer fmt.Println("3") } 結(jié)果: a 3 2 1 可以看到,在程序執(zhí)行完畢后,defer是從最后一條語(yǔ)句開(kāi)始執(zhí)行的,證明了defer類(lèi)似棧的運(yùn)行方式
defer搭配循環(huán)的結(jié)果
package main import "fmt" func main() { for i := 0; i < 3; i++ { defer fmt.Println(i) } } 結(jié)果: 2 1 0
panic/recover實(shí)例
主要用來(lái)對(duì)程序的控制,并且僅針對(duì)函數(shù)級(jí)別的錯(cuò)誤進(jìn)行收集與回調(diào)。使程序能繼續(xù)運(yùn)行下去
package main import "fmt" func main() { A() B() C() } func A() { fmt.Println("A") } func B() { defer func() { //這里定義defer執(zhí)行一個(gè)匿名函數(shù),用于捕捉panic,這里如果把defer放在panic之后那么程序執(zhí)行到panic后就會(huì)崩潰,那么defer就不會(huì)生效 if err := recover(); err != nil { //對(duì)引發(fā)的panic進(jìn)行判斷,由于手動(dòng)觸發(fā)了panic并發(fā)送了信息,那么用recover接收的異常返回值就要不為空,如果為nil表示沒(méi)有異常,不為nil就表示異常了,這里對(duì)recover的返回值進(jìn)行判斷 } }() panic("this is painc")//發(fā)送異常,異常信息為”this is panic“ } func C() { fmt.Println("C") } 結(jié)果: A C 由于在函數(shù)B中定義了異常的recover機(jī)制,所以不會(huì)迫使程序退出,會(huì)繼續(xù)執(zhí)行
panic/recover 實(shí)例2
package main import "fmt" func main() { fmt.Println("1") fmt.Println("2") f := func() { defer func() { if err := recover(); err != nil { fmt.Println("panic") } }() panic("hello world") fmt.Println("7") } f() fmt.Println("8") } 結(jié)果: 1 2 panic //打印panic說(shuō)明程序已經(jīng)成功的捕捉到了異常 8
定義了匿名函數(shù),并賦值給了變量f,匿名函數(shù)中的"7"不會(huì)打印,因?yàn)閳?zhí)行到panic已經(jīng)崩潰了,而我們?cè)谀涿瘮?shù)內(nèi)定義了recover捕捉,所以匿名函數(shù)會(huì)被退出,然后繼續(xù)執(zhí)行其他程序
擴(kuò)展:
在go語(yǔ)言中是沒(méi)有異常捕獲機(jī)制的,通過(guò)panic/recover來(lái)實(shí)現(xiàn)錯(cuò)誤的捕獲以及處理,利用go函數(shù)多返回值的概念,來(lái)進(jìn)行check,如果err等于nil表示沒(méi)有發(fā)生錯(cuò)誤,當(dāng)程序發(fā)生比較嚴(yán)重的錯(cuò)誤,嚴(yán)重到無(wú)法彌補(bǔ),比如索引越界,由于我們不能準(zhǔn)確的判斷元素的個(gè)數(shù),所以recover也沒(méi)有意義,所以說(shuō)這個(gè)時(shí)候就是一個(gè)panic。如果知道可能會(huì)索引越界,并且希望程序能從錯(cuò)誤中回復(fù)回來(lái),那么這時(shí)候就需要用到recover,一旦調(diào)用recover,系統(tǒng)就會(huì)認(rèn)為你需要從panic狀態(tài)恢復(fù)過(guò)來(lái),當(dāng)程序進(jìn)入panic狀態(tài),那么正常的程序?qū)⒉粫?huì)被執(zhí)行,那么需要定義defer來(lái)執(zhí)行recover(),defer不管在任何狀態(tài)下,都會(huì)執(zhí)行,只要把recover放在defer中,那么不管程序發(fā)生了怎樣的錯(cuò)誤,程序都會(huì)回復(fù)過(guò)來(lái),需要注意的是defer類(lèi)似棧的模式,后進(jìn)先出。在可能發(fā)生panic的程序之前,預(yù)先定義defer,否則程序運(yùn)行到painc后直接崩潰了,這個(gè)時(shí)候他只會(huì)去檢查預(yù)先定義好的defer,而你放在panic之后,將會(huì)失效
例子1:
判斷奇偶數(shù)
package main import "fmt" func main() { a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14} fmt.Println("the slice is ", a) fmt.Println("the odd is ", odd(a)) fmt.Println("the even is ", even(a)) } func odd(num []int) []int { var result []int for _, value := range num { if value%2 == 0 { result = append(result, value) } } return result } func even(num []int) []int { var result []int for _, value := range num { if value%2 == 0 { continue } result = append(result, value) } return result }
思路:分別對(duì)切片進(jìn)行過(guò)濾,偶數(shù)功能模塊過(guò)濾一遍,挑出偶數(shù),奇數(shù)功能模塊過(guò)濾一遍,挑出奇數(shù)。缺點(diǎn),模塊復(fù)用 性差。
判斷奇偶數(shù):
package main import ( "fmt" ) type funcation func(int) bool func odd(num int) bool { if num%2 == 0 { return false } return true } func even(num int) bool { if num%2 == 0 { return true } return false } func filter(slice []int, f funcation) []int { var result []int for _, value := range slice { if f(value) { result = append(result, value) } } return result } func main() { a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} fmt.Println("the slice is ", a) fmt.Println("the odd is ", filter(a, odd)) fmt.Println("the even is ", filter(a, even)) }
思路:把判斷奇偶的功能模塊化,然后再通過(guò)一個(gè)模塊調(diào)奇偶判斷模塊,然后再用main函數(shù)組織,(使用func類(lèi)型,進(jìn)行功能模塊的傳遞),有點(diǎn),結(jié)構(gòu)性強(qiáng),邏輯強(qiáng)。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線(xiàn),公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性?xún)r(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專(zhuān)為企業(yè)上云打造定制,能夠滿(mǎn)足用戶(hù)豐富、多元化的應(yīng)用場(chǎng)景需求。
分享名稱(chēng):golang學(xué)習(xí)筆記-func函數(shù)-創(chuàng)新互聯(lián)
網(wǎng)址分享:http://bm7419.com/article44/cdishe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站排名、網(wǎng)站導(dǎo)航、做網(wǎng)站、網(wǎng)站維護(hù)、小程序開(kāi)發(fā)、手機(jī)網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容