go語言20小時(shí)從入門到精通(五冯挎、函數(shù))

5.1 定義格式

函數(shù)構(gòu)成代碼執(zhí)行的邏輯結(jié)構(gòu)。在Go語言中咙鞍,函數(shù)的基本組成為:關(guān)鍵字func织堂、函數(shù)名叠艳、參數(shù)列表、返回值易阳、函數(shù)體和返回語句附较。

Go 語言函數(shù)定義格式如下:

func FuncName(/*參數(shù)列表*/) (o1 type1, o2 type2/*返回類型*/) {
    //函數(shù)體

    return v1, v2 //返回多個(gè)值
}

函數(shù)定義說明:

l func:函數(shù)由關(guān)鍵字 func 開始聲明

l FuncName:函數(shù)名稱,根據(jù)約定潦俺,函數(shù)名首字母小寫即為private拒课,大寫即為public

l 參數(shù)列表:函數(shù)可以有0個(gè)或多個(gè)參數(shù),參數(shù)格式為:變量名 類型事示,如果有多個(gè)參數(shù)通過逗號(hào)分隔早像,不支持默認(rèn)參數(shù)

l 返回類型:

① 上面返回值聲明了兩個(gè)變量名o1和o2(命名返回參數(shù)),這個(gè)不是必須肖爵,可以只有類型沒有變量名

② 如果只有一個(gè)返回值且不聲明返回值變量卢鹦,那么你可以省略,包括返回值的括號(hào)

③ 如果沒有返回值劝堪,那么就直接省略最后的返回信息

④ 如果有返回值冀自, 那么必須在函數(shù)的內(nèi)部添加return語句

5.2 自定義函數(shù)

5.2.1 無參無返回值

func Test() { //無參無返回值函數(shù)定義
    fmt.Println("this is a test func")
}

func main() {
    Test() //無參無返回值函數(shù)調(diào)用
}

5.2.2 有參無返回值

5.2.2.1 普通參數(shù)列表

func Test01(v1 int, v2 int) { //方式1
    fmt.Printf("v1 = %d, v2 = %d\n", v1, v2)
}

func Test02(v1, v2 int) { //方式2, v1, v2都是int類型
    fmt.Printf("v1 = %d, v2 = %d\n", v1, v2)
}

func main() {
    Test01(10, 20) //函數(shù)調(diào)用
    Test02(11, 22) //函數(shù)調(diào)用
}

5.2.2.2 不定參數(shù)列表

  1. 不定參數(shù)類型

不定參數(shù)是指函數(shù)傳入的參數(shù)個(gè)數(shù)為不定數(shù)量。為了做到這點(diǎn)秒啦,首先需要將函數(shù)定義為接受不定參數(shù)類型:

//形如...type格式的類型只能作為函數(shù)的參數(shù)類型存在熬粗,并且必須是最后一個(gè)參數(shù)
func Test(args ...int) {
    for _, n := range args { //遍歷參數(shù)列表
        fmt.Println(n)
    }
}

func main() {
    //函數(shù)調(diào)用,可傳0到多個(gè)參數(shù)
    Test()
    Test(1)
    Test(1, 2, 3, 4)
}

  1. 不定參數(shù)的傳遞
func MyFunc01(args ...int) {
    fmt.Println("MyFunc01")
    for _, n := range args { //遍歷參數(shù)列表
        fmt.Println(n)
    }
}

func MyFunc02(args ...int) {
    fmt.Println("MyFunc02")
    for _, n := range args { //遍歷參數(shù)列表
        fmt.Println(n)
    }
}

func Test(args ...int) {
    MyFunc01(args...)     //按原樣傳遞, Test()的參數(shù)原封不動(dòng)傳遞給MyFunc01
    MyFunc02(args[1:]...) //Test()參數(shù)列表中余境,第1個(gè)參數(shù)及以后的參數(shù)傳遞給MyFunc02
}

func main() {
    Test(1, 2, 3) //函數(shù)調(diào)用
}

5.2.3 無參有返回值

有返回值的函數(shù)驻呐,必須有明確的終止語句,否則會(huì)引發(fā)編譯錯(cuò)誤芳来。

5.2.3.1 一個(gè)返回值

func Test01() int { //方式1
    return 250
}

//官方建議:最好命名返回值含末,因?yàn)椴幻祷刂担m然使得代碼更加簡(jiǎn)潔了即舌,但是會(huì)造成生成的文檔可讀性差
func Test02() (value int) { //方式2, 給返回值命名
    value = 250
    return value
}

func Test03() (value int) { //方式3, 給返回值命名
    value = 250
    return
}

func main() {
    v1 := Test01() //函數(shù)調(diào)用
    v2 := Test02() //函數(shù)調(diào)用
    v3 := Test03() //函數(shù)調(diào)用
    fmt.Printf("v1 = %d, v2 = %d, v3 = %d\n", v1, v2, v3)
}

5.2.3.2 多個(gè)返回值

func Test01() (int, string) { //方式1
    return 250, "sb"
}

func Test02() (a int, str string) { //方式2, 給返回值命名
    a = 250
    str = "sb"
    return
}

func main() {
    v1, v2 := Test01() //函數(shù)調(diào)用
    _, v3 := Test02()  //函數(shù)調(diào)用答渔, 第一個(gè)返回值丟棄
    v4, _ := Test02()  //函數(shù)調(diào)用, 第二個(gè)返回值丟棄
    fmt.Printf("v1 = %d, v2 = %s, v3 = %s, v4 = %d\n", v1, v2, v3, v4)
}

5.2.4 有參有返回值

//求2個(gè)數(shù)的最小值和最大值
func MinAndMax(num1 int, num2 int) (min int, max int) {
    if num1 > num2 { //如果num1 大于 num2
        min = num2
        max = num1
    } else {
        max = num2
        min = num1
    }

    return
}

func main() {
    min, max := MinAndMax(33, 22)
    fmt.Printf("min = %d, max = %d\n", min, max) //min = 22, max = 33
}

5.3 遞歸函數(shù)

遞歸指函數(shù)可以直接或間接的調(diào)用自身侥涵。

遞歸函數(shù)通常有相同的結(jié)構(gòu):一個(gè)跳出條件和一個(gè)遞歸體。所謂跳出條件就是根據(jù)傳入的參數(shù)判斷是否需要停止遞歸宋雏,而遞歸體則是函數(shù)自身所做的一些處理芜飘。

//通過循環(huán)實(shí)現(xiàn)1+2+3……+100
func Test01() int {
    i := 1
    sum := 0
    for i = 1; i <= 100; i++ {
        sum += i
    }

    return sum
}

//通過遞歸實(shí)現(xiàn)1+2+3……+100
func Test02(num int) int {
    if num == 1 {
        return 1
    }

    return num + Test02(num-1) //函數(shù)調(diào)用本身
}

//通過遞歸實(shí)現(xiàn)1+2+3……+100
func Test03(num int) int {
    if num == 100 {
        return 100
    }

    return num + Test03(num+1) //函數(shù)調(diào)用本身
}

func main() {

    fmt.Println(Test01())    //5050
    fmt.Println(Test02(100)) //5050
    fmt.Println(Test03(1))   //5050
}

5.4 函數(shù)類型

type FuncType func(int, int) int //聲明一個(gè)函數(shù)類型, func后面沒有函數(shù)名

//函數(shù)中有一個(gè)參數(shù)類型為函數(shù)類型:f FuncType
func Calc(a, b int, f FuncType) (result int) {
    result = f(a, b) //通過調(diào)用f()實(shí)現(xiàn)任務(wù)
    return
}

func Add(a, b int) int {
    return a + b
}

func Minus(a, b int) int {
    return a - b
}

func main() {
    //函數(shù)調(diào)用,第三個(gè)參數(shù)為函數(shù)名字磨总,此函數(shù)的參數(shù)嗦明,返回值必須和FuncType類型一致
    result := Calc(1, 1, Add)
    fmt.Println(result) //2

    var f FuncType = Minus
    fmt.Println("result = ", f(10, 2)) //result =  8
}

5.5 匿名函數(shù)與閉包

所謂閉包就是一個(gè)函數(shù)“捕獲”了和它在同一作用域的其它常量和變量。這就意味著當(dāng)閉包被調(diào)用的時(shí)候蚪燕,不管在程序什么地方調(diào)用娶牌,閉包能夠使用這些常量或者變量奔浅。它不關(guān)心這些捕獲了的變量和常量是否已經(jīng)超出了作用域,所以只有閉包還在使用它诗良,這些變量就還會(huì)存在汹桦。

在Go語言里,所有的匿名函數(shù)(Go語言規(guī)范中稱之為函數(shù)字面量)都是閉包鉴裹。匿名函數(shù)是指不需要定義函數(shù)名的一種函數(shù)實(shí)現(xiàn)方式舞骆,它并不是一個(gè)新概念,最早可以回溯到1958年的Lisp語言径荔。

func main() {
    i := 0
    str := "mike"

    //方式1
    f1 := func() { //匿名函數(shù)督禽,無參無返回值
        //引用到函數(shù)外的變量
        fmt.Printf("方式1:i = %d, str = %s\n", i, str)
    }

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

    //方式1的另一種方式
    type FuncType func() //聲明函數(shù)類型, 無參無返回值
    var f2 FuncType = f1
    f2() //函數(shù)調(diào)用

    //方式2
    var f3 FuncType = func() {
        fmt.Printf("方式2:i = %d, str = %s\n", i, str)
    }
    f3() //函數(shù)調(diào)用

    //方式3
    func() { //匿名函數(shù),無參無返回值
        fmt.Printf("方式3:i = %d, str = %s\n", i, str)
    }() //別忘了后面的(), ()的作用是总处,此處直接調(diào)用此匿名函數(shù)

    //方式4, 匿名函數(shù)狈惫,有參有返回值
    v := func(a, b int) (result int) {
        result = a + b
        return
    }(1, 1) //別忘了后面的(1, 1), (1, 1)的作用是,此處直接調(diào)用此匿名函數(shù)鹦马, 并傳參
    fmt.Println("v = ", v)

}

閉包捕獲外部變量特點(diǎn):

func main() {
    i := 10
    str := "mike"
    func() {
        i = 100
        str = "go"
        //內(nèi)部:i = 100, str = go
        fmt.Printf("內(nèi)部:i = %d, str = %s\n", i, str)
    }() //別忘了后面的(), ()的作用是胧谈,此處直接調(diào)用此匿名函數(shù)

    //外部:i = 100, str = go
    fmt.Printf("外部:i = %d, str = %s\n", i, str)
}

函數(shù)返回值為匿名函數(shù):

// squares返回一個(gè)匿名函數(shù),func() int
// 該匿名函數(shù)每次被調(diào)用時(shí)都會(huì)返回下一個(gè)數(shù)的平方菠红。
func squares() func() int {
    var x int
    return func() int {//匿名函數(shù)
        x++ //捕獲外部變量
        return x * x
    }
}

func main() {
    f := squares()
    fmt.Println(f()) // "1"
    fmt.Println(f()) // "4"
    fmt.Println(f()) // "9"
    fmt.Println(f()) // "16"
}

函數(shù)squares返回另一個(gè)類型為 func() int 的函數(shù)第岖。對(duì)squares的一次調(diào)用會(huì)生成一個(gè)局部變量x并返回一個(gè)匿名函數(shù)。每次調(diào)用時(shí)匿名函數(shù)時(shí)试溯,該函數(shù)都會(huì)先使x的值加1蔑滓,再返回x的平方。第二次調(diào)用squares時(shí)遇绞,會(huì)生成第二個(gè)x變量键袱,并返回一個(gè)新的匿名函數(shù)。新匿名函數(shù)操作的是第二個(gè)x變量摹闽。

通過這個(gè)例子蹄咖,我們看到變量的生命周期不由它的作用域決定:squares返回后,變量x仍然隱式的存在于f中付鹿。

5.6 延遲調(diào)用defer

5.6.1 defer作用

func main() {
    fmt.Println("this is a test")
    defer fmt.Println("this is a defer") //main結(jié)束前調(diào)用

    /*
        運(yùn)行結(jié)果:
        this is a test
        this is a defer
    */
}

5.6.2 多個(gè)defer執(zhí)行順序

func test(x int) {
    fmt.Println(100 / x)//x為0時(shí)澜汤,產(chǎn)生異常
}

func main() {
    defer fmt.Println("aaaaaaaa")
    defer fmt.Println("bbbbbbbb")

    defer test(0)

    defer fmt.Println("cccccccc")
    /*
    運(yùn)行結(jié)果:
    cccccccc
    bbbbbbbb
    aaaaaaaa
    panic: runtime error: integer divide by zero
    */
}

5.6.3 defer和匿名函數(shù)結(jié)合使用

func main() {
    a, b := 10, 20
    defer func(x int) { // a以值傳遞方式傳給x
        fmt.Println("defer:", x, b) // b 閉包引用
    }(a)

    a += 10
    b += 100

    fmt.Printf("a = %d, b = %d\n", a, b)

    /*
        運(yùn)行結(jié)果:
        a = 20, b = 120
        defer: 10 120
    */
}

5.7 獲取命令行參數(shù)

package main

import (
    "fmt"
    "os"    //os.Args所需的包
)

func main() {
    args := os.Args //獲取用戶輸入的所有參數(shù)

    //如果用戶沒有輸入,或參數(shù)個(gè)數(shù)不夠,則調(diào)用該函數(shù)提示用戶
    if args == nil || len(args) < 2 {
        fmt.Println("err: xxx ip port")
        return
    }
    ip := args[1]   //獲取輸入的第一個(gè)參數(shù)
    port := args[2] //獲取輸入的第二個(gè)參數(shù)
    fmt.Printf("ip = %s, port = %s\n", ip, port)
}

運(yùn)行結(jié)果如下:


圖片.png

5.8 作用域

作用域?yàn)橐崖暶鳂?biāo)識(shí)符所表示的常量、類型舵匾、變量俊抵、函數(shù)或包在源代碼中的作用范圍。

5.8.1 局部變量

在函數(shù)體內(nèi)聲明的變量坐梯、參數(shù)和返回值變量就是局部變量徽诲,它們的作用域只在函數(shù)體內(nèi):

func test(a, b int) {
    var c int
    a, b, c = 1, 2, 3
    fmt.Printf("a = %d, b = %d, c = %d\n", a, b, c)
}

func main() {
    //a, b, c = 1, 2, 3 //err, a, b, c不屬于此作用域
    {
        var i int
        i = 10
        fmt.Printf("i = %d\n", i)
    }

    //i = 20 //err, i不屬于此作用域

    if a := 3; a == 3 {
        fmt.Println("a = ", a)
    }
    //a = 4 //err,a只能if內(nèi)部使用
}

5.8.2 全局變量

在函數(shù)體外聲明的變量稱之為全局變量,全局變量可以在整個(gè)包甚至外部包(被導(dǎo)出后)使用谎替。

var a int //全局變量的聲明

func test() {
   fmt.Printf("test a = %d\n", a)
}

func main() {
   a = 10
   fmt.Printf("main a = %d\n", a) //main a = 10

   test() //test a = 10
}

5.8.3 不同作用域同名變量

在不同作用域可以聲明同名的變量偷溺,其訪問原則為:在同一個(gè)作用域內(nèi),就近原則訪問最近的變量钱贯,如果此作用域沒有此變量聲明挫掏,則訪問全局變量,如果全局變量也沒有喷舀,則報(bào)錯(cuò)砍濒。

var a int //全局變量的聲明

func test01(a float32) {
    fmt.Printf("a type = %T\n", a) //a type = float32
}

func main() {
    fmt.Printf("a type = %T\n", a) //a type = int, 說明使用全局變量的a

    var a uint8 //局部變量聲明

    {
        var a float64                  //局部變量聲明
        fmt.Printf("a type = %T\n", a) //a type = float64
    }

    fmt.Printf("a type = %T\n", a) //a type = uint8

    test01(3.14)
    test02()
}

func test02() {
    fmt.Printf("a type = %T\n", a) //a type = int
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市硫麻,隨后出現(xiàn)的幾起案子爸邢,更是在濱河造成了極大的恐慌,老刑警劉巖拿愧,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件杠河,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡浇辜,警方通過查閱死者的電腦和手機(jī)券敌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來柳洋,“玉大人待诅,你說我怎么就攤上這事⌒芰停” “怎么了卑雁?”我有些...
    開封第一講書人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)绪囱。 經(jīng)常有香客問我测蹲,道長(zhǎng),這世上最難降的妖魔是什么鬼吵? 我笑而不...
    開封第一講書人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任扣甲,我火速辦了婚禮,結(jié)果婚禮上齿椅,老公的妹妹穿的比我還像新娘琉挖。我一直安慰自己,他們只是感情好涣脚,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開白布示辈。 她就那樣靜靜地躺著,像睡著了一般涩澡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評(píng)論 1 308
  • 那天妙同,我揣著相機(jī)與錄音射富,去河邊找鬼。 笑死粥帚,一個(gè)胖子當(dāng)著我的面吹牛胰耗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播芒涡,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼柴灯,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了费尽?” 一聲冷哼從身側(cè)響起赠群,我...
    開封第一講書人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎旱幼,沒想到半個(gè)月后查描,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡柏卤,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年冬三,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缘缚。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡勾笆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出桥滨,到底是詐尸還是另有隱情窝爪,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布该园,位于F島的核電站酸舍,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏里初。R本人自食惡果不足惜啃勉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望双妨。 院中可真熱鬧淮阐,春花似錦、人聲如沸刁品。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挑随。三九已至状您,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背膏孟。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來泰國打工眯分, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人柒桑。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓弊决,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親魁淳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子飘诗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • Lua 5.1 參考手冊(cè) by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 13,831評(píng)論 0 38
  • ??函數(shù)表達(dá)式是 JavaScript 中的一個(gè)既強(qiáng)大有容易令人困惑的特性昆稿。定義函數(shù)的的方式有兩種: 函數(shù)聲明; ...
    霜天曉閱讀 819評(píng)論 0 1
  • 〇仇奶、前言 本文共108張圖貌嫡,流量黨請(qǐng)慎重! 歷時(shí)1個(gè)半月该溯,我把自己學(xué)習(xí)Python基礎(chǔ)知識(shí)的框架詳細(xì)梳理了一遍岛抄。 ...
    Raxxie閱讀 18,966評(píng)論 17 410
  • 函數(shù)和對(duì)象 1、函數(shù) 1.1 函數(shù)概述 函數(shù)對(duì)于任何一門語言來說都是核心的概念狈茉。通過函數(shù)可以封裝任意多條語句夫椭,而且...
    道無虛閱讀 4,573評(píng)論 0 5
  • 夜蹭秋,很黑。鳥兒睡了堤撵,太陽睡了仁讨,月亮今天有沒有值班?我不知道实昨。外面隔著的洞豁,有兩扇門,有一道墻荒给,我看不見丈挟。星星呢?有沒...
    老姚打豆豆閱讀 346評(píng)論 0 0