Go基礎(chǔ)——function函數(shù)

函數(shù)的聲明

在 Go 語言中,函數(shù)聲明通用語法如下:

func 函數(shù)名稱( [參數(shù)列表] ) ([返回值列表])
{
  執(zhí)行語句
}

1.函數(shù)的聲明以關(guān)鍵詞 func開始 。

  1. 函數(shù)名和參數(shù)列表一起構(gòu)成了函數(shù)簽名越走。
  2. 參數(shù)列表定義在 () 之間缓呛,聲明一個參數(shù)的語法采用 參數(shù)名 參數(shù)類型 的方式催享,任意多個參數(shù)采用類似 (parameter1 type, parameter2 type) 即(參數(shù)1 參數(shù)1的類型,參數(shù)2 參數(shù)2的類型)的形式指定。參數(shù)是可選的哟绊,即函數(shù)可以不包含參數(shù)因妙。參數(shù)就像一個占位符,這是參數(shù)被稱為形參票髓,當(dāng)函數(shù)被調(diào)用時攀涵,將具體的值傳遞給參數(shù),這個值被稱為實際參數(shù)洽沟。
  3. Go函數(shù)支持多返回值以故。 函數(shù)可以有返回值也可以沒有。所以下面這個函數(shù)的聲明也是有效的:
func functionname() {  
}

我們以寫一個計算商品價格的函數(shù)為例裆操,輸入?yún)?shù)是單件商品的價格和商品的個數(shù)怒详,兩者的乘積為商品總價,作為函數(shù)的輸出值踪区。

func calculateBill(price int, no int) int {  
    var totalPrice = price * no // 商品總價 = 商品單價 * 數(shù)量
    return totalPrice // 返回總價
}

上述函數(shù)有兩個整型的輸入 priceno昆烁,返回值 totalPricepriceno 的乘積,也是整數(shù)類型缎岗。
如果有連續(xù)若干個參數(shù)静尼,它們的類型一致,那么我們無須一一羅列,只需在最后一個參數(shù)后添加該類型鼠渺。*例如鸭巴,price int, no int可以簡寫為 price, no int,所以示例函數(shù)也可寫成

func calculateBill(price, no int) int {  
    var totalPrice = price * no
    return totalPrice
}

現(xiàn)在我們已經(jīng)定義了一個函數(shù)拦盹,我們要在代碼中嘗試著調(diào)用它鹃祖。調(diào)用函數(shù)的語法為 functionname(parameters)。調(diào)用示例函數(shù)的方法如下:

calculateBill(10, 5)

完成了示例函數(shù)聲明和調(diào)用后掌敬,我們就能寫出一個完整的程序惯豆,并把商品總價打印在控制臺上:

func calculateBill(price, no int) int {  
    var totalPrice = price * no
    return totalPrice
}
func main() {  
    price, no := 90, 6 // 定義 price 和 no,默認(rèn)類型為 int
    totalPrice := calculateBill(price, no)
    fmt.Println("Total price is", totalPrice) // 打印到控制臺上
}

函數(shù)調(diào)用

如果函數(shù)和調(diào)用不在同一個包(package)內(nèi),需要先通過import關(guān)鍵字將包引入–import “fmt”奔害。函數(shù)Println()就屬于包fmt楷兽。與其他語言不同的是在Go語言中函數(shù)名字的大小寫不僅僅是風(fēng)格,更直接體現(xiàn)了該函數(shù)的是私有函數(shù)還是公有函數(shù)华临。函數(shù)名首字母小寫為private,大寫為public芯杀。

package utiles

func Max(a,b int )(m int){
    if a>b {
        return a
    }
    return b
}

Max 函數(shù)如果被其他包調(diào)用 首字母需要大寫

import (
    "utiles"
    "fmt"
)

func min(a ,b int) (m int){
    if a>b {
        return b
    }
    return a
}

func main(){
   r := utiles.Max(2,4)
   d  := min(2,4)
   fmt.Println(r,d)
}

多個返回值

Go 語言支持一個函數(shù)可以有多個返回值。

import (
    "fmt"
)
func swap(a string,b string)(string,string){
    return b,a;
}

func main() {
    a,b :=swap("abc","def")
    fmt.Println(a,b)
}

如果調(diào)用方調(diào)用了一個具有多返回值的方法雅潭,但是卻不想關(guān)心其中的某個返回值揭厚,用一個下劃線 _ 來忽略這個返回值。如同一個占位符號扶供,如果我們只關(guān)注第一個返回值則可以寫成:

a, _ := swap("hello", "world")

如果關(guān)注第二返回值則可以寫成:

_, b := swap("hello", "world")

函數(shù)參數(shù)

1.值傳遞:調(diào)用函數(shù)時將實際參數(shù)復(fù)制一份傳遞到函數(shù)中筛圆,這樣在函數(shù)中如果對參數(shù)進行修改,將不會影響到實際參數(shù)椿浓。
2.引用傳遞:調(diào)用函數(shù)時將實際參數(shù)復(fù)制一份傳遞到函數(shù)中太援,這樣在函數(shù)中如果對參數(shù)進行修改,將不會影響到實際參數(shù)扳碍。

import (
"fmt"

)
func changeValue(a string){
     a = "new value"
}

func change(a *string){
    *a = "new value2"
}

func main() {
    a := "old value"
    changeValue(a)
    fmt.Println(a)
    change(&a)
    fmt.Println(a)
    /*
    print result:
    old value     
    new value2
    */
}

返回值

從函數(shù)中可以返回一個命名值提岔。一旦命名了返回值,可以認(rèn)為這些值在函數(shù)第一行就被聲明為變量了笋敞。命名返回值作為結(jié)果形參(result parameters)被初始化為相應(yīng)類型的零值碱蒙,當(dāng)需要返回的時候,我們只需要一條簡單的不帶參數(shù)的return語句夯巷。

func getResult(input int) (a int, b int) {
    a = 2 * input
    b = 3 * input
    return
}
func main() {
    n,m:= getResult(2);
    fmt.Print(n,m)
}

函數(shù)中的 return 語句沒有顯式返回任何值赛惩。由于a 和 b 在函數(shù)聲明中指定為返回值, 因此當(dāng)遇到 return 語句時, 它們將自動從函數(shù)返回。

可變參數(shù)

Go函數(shù)支持不定數(shù)量的參數(shù)的趁餐。為了做到這點喷兼,首先需要定義函數(shù)使其接受變參,類型“…type“本質(zhì)上是一個數(shù)組切片,也就是[]type澎怒,

func funcName(arg ...type) {
}

arg ...type告訴Go這個函數(shù)接受不定數(shù)量的參數(shù)。在下面的例子中參數(shù)的類型全部是int。在函數(shù)體中喷面,變量arg是一個int的slice.
在參數(shù)賦值時可以不用用一個一個的賦值星瘾,可以直接傳遞一個數(shù)組或者切片,特別注意的是在參數(shù)后加上“…”即可惧辈。

import (
    "fmt"
)

func min(a...int) int{
    if len(a)==0 {
        return 0

    }
    min := a[0]
    for _,v :=range a{
        if min >v {
            min = v
        }
    }
    return min;
}

func main() {
    n := min(7,12,3,9,8)
    arr := []int {45,27,60,67,18}
    r := min(arr...)
    m := min(arr[:3]...)
    fmt.Print(n,r,m)
}

那么如果函數(shù)的參數(shù)類型不一致需要使用interface{}

import (
    "fmt"
    "reflect"
)

func diffType(args ...interface{}){
    for _, arg :=range args {
        fmt.Println(arg)
        fmt.Println(reflect.TypeOf(arg))
    }
}
func main() {
    diffType("test",1,12.5,[5]byte{1,3,4})
}

defer

return 可以返回 函數(shù)執(zhí)行的結(jié)果值琳状,通過關(guān)鍵字 defer 允許我們推遲到函數(shù)返回之前(或任意位置執(zhí)行 return 語句之后)一刻才執(zhí)行某個語句或函數(shù),這樣return不是單純地返回某個值盒齿,同樣可以包含一些操作念逞。
注意:多個defer語句 遵循棧的特征:先進后出

func testDefer() {
    defer fmt.Println("hello")
    defer fmt.Println("hello v2")
    defer fmt.Println("hello v3")
    fmt.Println("aaaaa")
    fmt.Println("bbbb")
}
func testDefer2() {
    var i int = 0
    defer fmt.Printf("defer i=%d\n", i)
    i= 1000
    fmt.Printf("i=%d\n", i)
}

func main() {
     testDefer()
     testDefer2()
}

匿名函數(shù)

匿名函數(shù)由一個不帶函數(shù)名的函數(shù)聲明和函數(shù)體組成,比如:

func(x边翁,y int) int {
    return x + y
}

Go中函數(shù)是值類型翎承,即可以作為參數(shù),又可以作為返回值符匾。
匿名函數(shù)可以賦值給一個變量:

f := func() int {
    ...
}

定義函數(shù)類型:

type CalcFunc func(x,y int ) int 

函數(shù)作為參數(shù):

func Add(x, y int) int {
    return x + y
}

func Sub(x, y int) int {
    return x - y
}

type CalcFunc func(x,y int ) int 

func Operation(x, y int, calcFunc CalcFunc) int {
    return calcFunc(x, y)
}

func main() {
    sum := Operation(1, 2, Add)
    difference := Operation(1, 2, Sub)
    fmt.Println(sum,difference)
}

函數(shù)可以作為返回值:

// 第一種寫法
func add(x, y int) func() int {
    f := func() int {
        return x + y
    }
    return f
}

// 第二種寫法
func add(x, y int) func() int {
    return func() int {
        return x + y
    }
}

閉包

避免程序運行時異常崩潰

Golang中對于一般的錯誤處理提供了error接口叨咖,對于不可預(yù)見的錯誤(異常)處理提供了兩個內(nèi)置函數(shù)panic和recover。error接口類似于C/C++中的錯誤碼啊胶,panic和recover類似于C++中的try/catch/throw甸各。
當(dāng)在一個函數(shù)執(zhí)行過程中調(diào)用panic()函數(shù)時,正常的函數(shù)執(zhí)行流程將立即終止焰坪,但函數(shù)中之前使用defer關(guān)鍵字延遲執(zhí)行的語句將正常展開執(zhí)行趣倾,之后該函數(shù)將返回到調(diào)用函數(shù),并導(dǎo)致逐層向上執(zhí)行panic流程某饰,直至所屬的goroutine中所有正在執(zhí)行的函數(shù)被終止儒恋。錯誤信息將被報告,包括在調(diào)用panic()函數(shù)時傳入的參數(shù)露乏,這個過程稱為異常處理流程碧浊。
recover函數(shù)用于終止錯誤處理流程。一般情況下瘟仿,recover應(yīng)該在一個使用defer關(guān)鍵字的函數(shù)中執(zhí)行以有效截取錯誤處理流程箱锐。如果沒有在發(fā)生異常的goroutine中明確調(diào)用恢復(fù)過程(調(diào)用recover函數(shù)),會導(dǎo)致該goroutine所屬的進程打印異常信息后直接退出劳较。

對于第三方庫的調(diào)用驹止,在不清楚是否有panic的情況下,最好在適配層統(tǒng)一加上recover過程观蜗,否則會導(dǎo)致當(dāng)前進程的異常退出臊恋,而這并不是我們所期望的。
簡單的實現(xiàn)如下:

func thirdPartyAdaptedHandler(...) {
    defer func() {
        err := recover()
        if err != nil {
            fmt.Println("some exception has happend:", err)
        }
    }()
    ...
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末墓捻,一起剝皮案震驚了整個濱河市抖仅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖撤卢,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件环凿,死亡現(xiàn)場離奇詭異,居然都是意外死亡放吩,警方通過查閱死者的電腦和手機智听,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來渡紫,“玉大人到推,你說我怎么就攤上這事√枧欤” “怎么了莉测?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長集灌。 經(jīng)常有香客問我悔雹,道長,這世上最難降的妖魔是什么欣喧? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任腌零,我火速辦了婚禮,結(jié)果婚禮上唆阿,老公的妹妹穿的比我還像新娘益涧。我一直安慰自己,他們只是感情好驯鳖,可當(dāng)我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布闲询。 她就那樣靜靜地躺著,像睡著了一般浅辙。 火紅的嫁衣襯著肌膚如雪扭弧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天记舆,我揣著相機與錄音鸽捻,去河邊找鬼。 笑死泽腮,一個胖子當(dāng)著我的面吹牛御蒲,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播诊赊,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼厚满,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了碧磅?” 一聲冷哼從身側(cè)響起碘箍,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤遵馆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后丰榴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體团搞,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年多艇,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片像吻。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡峻黍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拨匆,到底是詐尸還是另有隱情姆涩,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布惭每,位于F島的核電站骨饿,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏台腥。R本人自食惡果不足惜宏赘,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望黎侈。 院中可真熱鬧察署,春花似錦、人聲如沸峻汉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽休吠。三九已至扳埂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間瘤礁,已是汗流浹背阳懂。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蔚携,地道東北人希太。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像酝蜒,于是被迫代替她去往敵國和親誊辉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,941評論 2 355