Go语言基础02——函数、工程管理

函数的基本使用

函数构成代码执行的逻辑结构。在Go语言中,函数的基本组成为:关键字func、函数名、参数列表、返回值、函数体和返回语句。

函数定义说明:
l func:函数由关键字 func 开始声明
l FuncName:函数名称,根据约定,函数名首字母小写即为private,大写即为public
l 参数列表:函数可以有0个或多个参数,参数格式为:变量名 类型,如果有多个参数通过逗号分隔,不支持默认参数
l 返回类型:
① 上面返回值声明了两个变量名o1和o2(命名返回参数),这个不是必须,可以只有类型没有变量名
② 如果只有一个返回值且不声明返回值变量,那么你可以省略,包括返回值的括号
③ 如果没有返回值,那么就直接省略最后的返回信息
④ 如果有返回值, 那么必须在函数的内部添加return语句

下面通过代码讲述函数的基本使用:

package main

import "fmt"

func sing() {
    fmt.Println("i am singing!")
}

func sing2(lrc string) { // 注意不能与sing()函数重名
    fmt.Println("i am singing : " + lrc)
}
func sing3(args ...string) { // 注意不能与sing()函数重名

    for _, data := range args {
        fmt.Println("i am singing : " + data)
    }

}

func sing4(args ...string) { // 注意不能与sing()函数重名
    sing3(args[:2]...)
}
func sing5(args ...string) { // 注意不能与sing()函数重名
    sing3(args[2:]...)
}
func myfunc01() int {
    return 666
}

func myfunc02() (result int) { // go语言推荐写法
    return 777
}
func myfunc03() (result int) { // go语言推荐写法
    result = 888
    return
}

func calc(a, b int) (r1, r2 int) { // go语言推荐写法
    r1 = a + b
    r2 = a * b
    return
}

func main() {
    fmt.Println("函数的基本使用演示案例")

    // 1. 无参数无返回值
    sing()
    // 2. 有参数无返回值:普通参数列表
    sing2("我爱go语言")

    // 3. 有参数无返回值:不定参数类型
    sing3("A", "B", "C")
    sing3("哈哈哈")
    sing3()
    fmt.Println("==========")
    // 4. 不定参数的传递
    sing4("x", "y", "z", "666") // x,y
    fmt.Println("==========")
    sing5("x", "y", "z", "666") // z,666

    // 5. 带返回值的函数:有返回值的函数,必须有明确的终止语句,否则会引发编译错误。
    res := myfunc01()
    fmt.Println("res = ", res)
    res2 := myfunc02()
    fmt.Println("res2 = ", res2)
    res3 := myfunc03()
    fmt.Println("res3 = ", res3)

    // 6. 函数返回多个返回值

    a, b := calc(4, 5)
    fmt.Printf("a+b = %d,a*b=%d", a, b)
}

递归函数

package main

import "fmt"

func add(i int) int {
    if i == 1 {
        return 1
    } else {
        return i + add(i-1)
    }

}

func main() {
    fmt.Println("函数的基本使用演示案例")
    result := add(100)
    fmt.Println("1-100的和是 :", result)

}

函数类型

在Go语言中,函数也是一种数据类型,我们可以通过type来定义它,它的类型就是所有拥有相同的参数,相同的返回值的一种类型。

package main

import "fmt"

func add(a, b int) int {
    return a + b
}
func sub(a, b int) int {
    return a - b
}

type FuncType func(a, b int) int //没有函数名字,没有函数实体{}

func main() {
    fmt.Println("函数类型的使用演示案例")

    var calc FuncType
    calc = add
    r1 := calc(1, 2)
    fmt.Println("r1 :", r1)

    calc = sub
    r2 := calc(8, 2)
    fmt.Println("r2 :", r2)

}

回调函数

函数参数是函数类型,这个函数就是回调函数。

package main

import "fmt"

func add(a, b int) int {
    return a + b
}
func sub(a, b int) int {
    return a - b
}

type FuncType func(a, b int) int //没有函数名字,没有函数实体{}

// 回调函数,函数有一个参数是函数类型,这个函数就是回调函数

func Calc(a, b int, f FuncType) int {
    return f(a, b)
}

func main() {
    fmt.Println("回调函数的使用演示案例")

    m1 := add
    r1 := Calc(1, 2, m1)
    fmt.Println("r1 = ", r1)

    m1 = sub
    r1 = Calc(1, 2, m1)
    fmt.Println("r1 = ", r1)
}

匿名函数和闭包

所谓闭包就是一个函数“捕获”了和它在同一作用域的其它常量和变量。这就意味着当闭包被调用的时候,不管在程序什么地方调用,闭包能够使用这些常量或者变量。它不关心这些捕获了的变量和常量是否已经超出了作用域,所以只有闭包还在使用它,这些变量就还会存在。

在Go语言里,所有的匿名函数(Go语言规范中称之为函数字面量)都是闭包。匿名函数是指不需要定义函数名的一种函数实现方式,它并不是一个新概念,最早可以回溯到1958年的Lisp语言。

闭包以引用方式捕获外部变量

package main

import "fmt"

func main() {
    fmt.Println("匿名函数和闭包的使用演示案例")
    a := 10
    str := "abc"

    ///1、匿名函数,没有函数名字,没有函数定义,也没有调用
    f1 := func() {
        fmt.Printf("a = %d, str = %s\n", a, str)
    }
    f1()

    // 2、给函数类型起别名
    type MyFunc func()
    var v1 MyFunc

    v1 = f1
    v1()

    //3、有带参数的匿名函数

    f2 := func(a, b int) {
        fmt.Printf("a = %d, b = %d\n", a, b)
    }
    f2(3, 4)

    // 匿名函数,同时调用
    func(a, b int) {
        fmt.Printf("a = %d, b = %d\n", a, b)
    }(55, 66)

    //4、匿名函数,有参数有返回值:

    res := func(a, b int) int {
        return a + b
    }(2, 3)
    fmt.Printf("res = %d \n", res)

    // 5、闭包:闭包以引用方式捕获外部变量
    aa := 10
    bb := "abc"

    func() {
        aa = 20
        bb = "zzz"
        fmt.Printf("内部 a = %d, b = %s\n", aa, bb) //内部 a = 20, b = zzz
    }()
    fmt.Printf("外部 a = %d, b = %s\n", aa, bb) //外部 a = 20, b = zzz

    fmt.Println("test01 = ", test01()) //1
    fmt.Println("test01 = ", test01()) //1

    fmt.Println("test02 = ", test02()) //1
    fmt.Println("test02 = ", test02()) //1
    fmt.Println("test02 = ", test02()) //1

    f3 := test02()
    fmt.Println("test02 f3 = ", f3()) //1
    fmt.Println("test02 f3 = ", f3()) //4
    fmt.Println("test02 f3 = ", f3()) //9

    //函数test02返回另一个类型为 func() int 的函数。
    //对test02的一次调用会生成一个局部变量x并返回一个匿名函数。
    //每次调用时匿名函数时,该函数都会先使x的值加1,再返回x的平方。
    //第二次调用test02时,会生成第二个x变量,并返回一个新的匿名函数。新匿名函数操作的是第二个x变量。
    //通过这个例子,我们看到变量的生命周期不由它的作用域决定:test02返回后,变量x仍然隐式的存在于f中。
}

func test01() int {
    var n int
    n++
    return n * n
}

// 函数返回是一个匿名函数,
func test02() func() int {
    var n int

    return func() int {
        n++
        return n * n
    }

}

defer的使用

关键字 defer ⽤于延迟一个函数或者方法(或者当前所创建的匿名函数)的执行。注意,defer语句只能出现在函数或方法的内部。

defer语句经常被用于处理成对的操作,如打开、关闭、连接、断开连接、加锁、释放锁。通过defer机制,不论函数逻辑多复杂,都能保证在任何执行路径下,资源被释放。释放资源的defer应该直接跟在请求资源的语句后。

package main

import "fmt"

func main() {
    fmt.Println("defer的使用演示案例")

    fmt.Println("aaaaaaa")

    defer fmt.Println("bbbbbbb")

    fmt.Println("ccccccc")

    // aaa ccc bbb
}

多个defer的调用顺序:

package main

import "fmt"

func main() {
    fmt.Println("多个defer的调用顺序使用演示案例")

    defer fmt.Println("aaaaaaa")

    defer fmt.Println("bbbbbbb")

    fmt.Println("ccccccc")

    //  ccc bbb aaa
}

defer和匿名函数的结合:

package main

import "fmt"

func main() {
    fmt.Println("defer和匿名函数的结合使用演示案例")

    // 情形一
    a := 10
    b := "abc"
    defer func() {
        fmt.Printf("内部:a = %d,b = %s\n", a, b)
    }()

    a = 20
    b = "zz"

    fmt.Printf("外部:a = %d,b = %s\n", a, b)
}

defer和匿名函数的结合2:

package main

import "fmt"

func main() {
    fmt.Println("defer和匿名函数的结合使用演示案例")

    // 情形二
    a := 10
    b := "abc"
    defer func(a int, b string) {
        fmt.Printf("内部:a = %d,b = %s\n", a, b) // 内部:a = 10,b = abc
    }(a, b)

    a = 20
    b = "zz"

    fmt.Printf("外部:a = %d,b = %s\n", a, b) //外部:a = 20,b = zz
}

获取命令行参数

package main

import "fmt"
import "os"

func main() {
    fmt.Println("获取命令行 使用演示案例")

    args := os.Args
    fmt.Println("len = ", len(args))

    for i, data := range args {
        fmt.Println("data[%d] = %s", i, data)
    }
}

导入包

. 点操作:

package main

// 方式一
// import "fmt"
// import "os"

// 方式二
// import (
//  "fmt"
//  "os"
// )

// 方式三

import . "os" // 调用函数无需通过包名
import . "fmt"

func main() {
    // fmt.Println("导入包使用演示案例")// 如果使用了.操作,则不能这样引用了
    // args := os.Args
    // fmt.Println("len = ", len(args))

    args := Args
    Println("len = ", len(args))

}

给包起别名:

package main

import pt "fmt"
import ooss "os"

func main() {
    pt.Println("导入包使用演示案例") // 如果使用了.操作,则不能这样引用了
    args := ooss.Args
    // fmt.Println("len = ", len(args))// err,起完别名之后不能这样使用了
    pt.Println("len = ", len(args)) // err,起完别名之后不能这样使用了
}

忽略此包:

import _ "fmt"

其他

过程管理、gopath、init、go install

END.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容