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.

你可能感兴趣的:(Go语言基础02——函数、工程管理)