Golang函數(shù)的使用

函數(shù)

在GO語言中吠式,函數(shù)的基本組成為func關(guān)鍵字陡厘,函數(shù)名,參數(shù)列表特占,返回值糙置,函數(shù)體和返回語句。

1. 函數(shù)的定義

首先是目,我們通過一個最簡單的加法函數(shù)來進行說明

package mymath

import "errors"

func Add(a int, b int) (ret int, err error) {
    if a < 0 || b < 0 { //假定函數(shù)只支持兩個非負(fù)數(shù)相加
        err = errors.New("Should be non-negative numbers")
        return
    }
    return a + b, nil //支持多返回值
}

上面的函數(shù)中谤饭,(ret int, err error)表示多返回值,error是Go中特有的錯誤處理包懊纳。
后面我們會單獨介紹這個包揉抵。

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

Go語言的函數(shù)調(diào)用非常簡單,只要事先導(dǎo)入了該包嗤疯。我們就可以按照如下方式調(diào)用冤今。

import "mymath" //第1節(jié)中,我們定義了mymath包茂缚,這里我們導(dǎo)入這個包

c := mymath.Add(1, 2) 

注意在Go語言中戏罢,函數(shù)名以大寫字母開頭,才會被包導(dǎo)出脚囊,如果你不小心將上面的函數(shù)寫為
func add(a int, b int)帖汞,這樣在mymath.add(1, 2)使用時,編譯器會告訴你無法
找到add函數(shù)凑术。也就是說翩蘸,小寫字母開頭的函數(shù),在包外部是不可引用的淮逊。

3. 不定參數(shù)

在C語言時代催首,大家都用過printf()函數(shù)扶踊,不定參數(shù)帶給我們的方便想必大家已經(jīng)領(lǐng)略過了。下面
我們看看Go語言是如何支持不定參數(shù)的郎任。

3.1 不定參數(shù)類型

我們首先把函數(shù)定義為接收不定參數(shù)類型:

func myfunc(args ...int) {
    for _, arg := range args {
        fmt.Println(arg)
    }
}

這段代碼的意思是myfunc函數(shù)接收不定數(shù)量的參數(shù)秧耗,這些參數(shù)全是int,所以要按照如下方式
調(diào)用:

myfunc(1, 2, 3, 4)
myfunc(2, 3, 5)

在上面的不定參數(shù)定義中舶治,形入...type格式的類型只能作為函數(shù)的參數(shù)類型存在分井。并且必須是
最后一個參數(shù)。\

語法糖(syntactic sugar) ...type這樣的語法對語言的功能并沒有影響霉猛,但是更方便程序員
的調(diào)用尺锚。通常來說,使用語法糖能夠增加程序的可讀性惜浅,從而減少程序出錯的機會瘫辩。
從內(nèi)部實現(xiàn)上來說,類型...type本質(zhì)上是一個數(shù)組切片坛悉,也就是[]type伐厌,這也是上面為什么能
用range遍歷的原因。
如果沒有...type語法糖裸影,則開發(fā)者就必須這樣寫:

func myfunc(args []int) {
    for _, arg := range args {
        fmt.Println(arg)
    }
}

從函數(shù)的角度看挣轨,沒有語法糖并沒有什么影響,只是寫法不同而已轩猩。
但是卷扮,從調(diào)用的角度來看,情況就完全不同界轩。

myfunc([]int{1, 2, 3,4})

對比使用...type語法糖實現(xiàn)來看,調(diào)用時的寫法會打不相同衔瓮,語法糖使我們使用不定參數(shù)
更加便捷浊猾。

3.2 不定參數(shù)的傳遞

假設(shè)有另一個不定函數(shù)叫做myfunc2(arg ...int).

func myfunc(args ...int) {
    myfunc2(args...)  //按原樣傳遞
    myfunc2(args[1:]...) //slice的特性在這里也可以使用
}

3.3 任意類型的不定參數(shù)

上面的例子中,我們將不定參數(shù)類型定為int型热鞍。下面我們來看看傳遞任意類型的實現(xiàn)葫慎。
我們不定參數(shù)類型知道為interface{},下面是fmt.Printf()函數(shù)原型

func Printf(format string, args ...interface{})

下面代碼展示了如何分離傳入的不同類型數(shù)據(jù)

package main

import "fmt"

func MyPrintf(args ...interface{}) {
    for _, arg := range args {
        switch arg.(type) {
            case int:
                fmt.Println(arg, "is an int value.")
            case string:
                fmt.Println(arg, "is an string value.")
            case int64:
                fmt.Println(arg, "is an int64 value.")
            case default:
                fmt.Println(arg, "is an unknown value.")
        }
    }
}

4. 多返回值

不同于C語言薇宠,Go語言一個函數(shù)可以有多個返回值偷办,這樣能讓我們的代碼更加簡潔。
比如File.Read()函數(shù)澄港,可以同時返回讀取的字節(jié)數(shù)和錯誤信息椒涯,如果讀取成功,則返回
值中的n為讀取的字節(jié)數(shù)回梧,err為nil废岂。否則祖搓,err為錯誤信息。

Func (file *File) Read(b []byte) (n int, err error) {}

Go語言不需要強制命名返回值湖苞,但是命名返回值可以讓代碼更清晰拯欧,也可用于文檔。
如果我們不想使用某個返回值财骨,可以用 "_"忽略镐作,例如:

n, _ := f.Read(buf) //忽略返回的錯誤信息

5. 匿名函數(shù)與閉包

匿名函數(shù)是指不需要定義函數(shù)名的一種函數(shù)實現(xiàn)方式。

5.1 匿名函數(shù)

匿名函數(shù)定義如下

func(a, b int, z float64) bool {
    return a*b < int(z)
}

匿名函數(shù)可以直接賦值給一個變量

f := func(x, y int) int {
    return x + y
}

func (ch chan int) {
    ch <- ACK
} (reply_chan) //花括號后面跟參數(shù)列表隆箩,表示函數(shù)調(diào)用

5.2 閉包

匿名函數(shù)是一個閉包该贾。下面我們來了解一下閉包的概念,價值和應(yīng)用場景摘仅。

基本概念

閉包是可以包含自由(未綁定到特定對象)變量的代碼塊靶庙。這些變量不在這個代碼塊內(nèi)或者
任何全局上下文,而是在定義代碼塊的環(huán)境中定義娃属。要執(zhí)行的代碼塊為自由變量提供綁定的計算
環(huán)境(作用域)

閉包的價值

閉包的價值在于可以作為函數(shù)對象或者匿名函數(shù)六荒。對象類型系統(tǒng)而言,這意味著不僅要表示數(shù)據(jù)矾端,
還要表示代碼掏击。這些函數(shù)可以存儲到變量中作為參數(shù)傳遞給其他函數(shù),最重要的是能夠被函數(shù)
動態(tài)創(chuàng)建和返回秩铆。

Go語言中的閉包

Go語言中的閉包同樣也會引用到函數(shù)外的變量砚亭。閉包的實現(xiàn)確保只要閉包還被使用,那么殴玛,被閉包
引用的變量會一直存在捅膘。

package main

import (
    "fmt"
)

func main() {
    var j int = 5
    
    a := func() (func()) {
        var i int = 10
        return func() {
            fmt.Printf("i, j: %d, %d\n", i, j)
        }
    } ()
    
    a()
    
    j += 2
    
    a()
}

上述代碼執(zhí)行的結(jié)果為:

i, j: 10, 5
i, j: 10, 7

上面的例子中,變量a指向的閉包函數(shù)引用了局部變量i和j滚粟,i的值被隔離寻仗,在閉包之外不可被
修改。只要匿名函數(shù)內(nèi)部才能修改i的值凡壤,保證了i的安全性署尤。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市亚侠,隨后出現(xiàn)的幾起案子曹体,更是在濱河造成了極大的恐慌,老刑警劉巖硝烂,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件箕别,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機究孕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門啥酱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人厨诸,你說我怎么就攤上這事镶殷。” “怎么了微酬?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵绘趋,是天一觀的道長。 經(jīng)常有香客問我颗管,道長陷遮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任垦江,我火速辦了婚禮帽馋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘比吭。我一直安慰自己绽族,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布衩藤。 她就那樣靜靜地躺著吧慢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赏表。 梳的紋絲不亂的頭發(fā)上检诗,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天,我揣著相機與錄音瓢剿,去河邊找鬼逢慌。 笑死,一個胖子當(dāng)著我的面吹牛间狂,可吹牛的內(nèi)容都是我干的攻泼。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼前标,長吁一口氣:“原來是場噩夢啊……” “哼坠韩!你這毒婦竟也來了距潘?” 一聲冷哼從身側(cè)響起炼列,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎音比,沒想到半個月后俭尖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年稽犁,在試婚紗的時候發(fā)現(xiàn)自己被綠了焰望。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡已亥,死狀恐怖熊赖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情虑椎,我是刑警寧澤震鹉,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站捆姜,受9級特大地震影響传趾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜泥技,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一浆兰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧珊豹,春花似錦、人聲如沸平夜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽忽妒。三九已至,卻和暖如春吃溅,著一層夾襖步出監(jiān)牢的瞬間决侈,已是汗流浹背喧务。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工庐冯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留坎穿,地道東北人展父。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓返劲,卻偏偏與公主長得像,于是被迫代替她去往敵國和親栖茉。 傳聞我的和親對象是個殘疾皇子篮绿,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,077評論 2 355