函数-function

函数是一块执行特定任务的代码。一个函数是在输入源基础上,通过执行一系列的算法,生成预期的输出。

 

1 函数的声明

在 Go 语言中,函数声明通用语法如下:

func 函数名(参数名1 类型,参数名2 类型)(返回值1类型,返回值2类型){
    函数体内容
    return 返回值1,返回值2
    }

函数的声明以关键词 func 开始,后面紧跟自定义的函数名 functionname (函数名)。函数的参数列表定义在 ( 和 ) 之间,返回值的类型则定义在之后的 returntype (返回值类型)处。声明一个参数的语法采用 参数名 参数类型 的方式,任意多个参数采用类似 (parameter1 type, parameter2 type) 即(参数1 参数1的类型,参数2 参数2的类型)的形式指定。之后包含在 { 和 } 之间的代码,就是函数体。

函数中的参数列表和返回值并非是必须的,所以下面这个函数的声明也是有效的

func functionname() {  
    // 译注: 表示这个函数不需要输入参数,且没有返回值
}

注意:go语言中,函数的调用,没有关键字传参,没有默认参数,只有位置传参。

 

2 函数的基本使用

2.1 有参数无返回值

package main

import "fmt"

func main() {
    add(2, 3)  //调用函数
}

//定义函数
func add(a int, b int) {
    fmt.Println(a + b)
}

如果有连续若干个参数,它们的类型一致,那么我们无须一一罗列,只需在最后一个参数后添加该类型。 例如,a int, b int 可以简写为 a, b int,所以上例也可写成:

package main

import "fmt"

func main() {
    add(2, 3)  //调用函数
}

//定义函数
func add(a, b int) {
    fmt.Println(a + b)
}

2.2 有参数无返回值,有多个相同类型参数,也有不同类型参数

package main

import "fmt"

func main() {
    add(2, 3, "nb") //调用函数
}

//定义函数
func add(a, b int, msg string) {
    fmt.Println(a + b)
    fmt.Printf(msg)
}

2.3 有多个参数,一个返回值

package main

import "fmt"

func main() {
    //var res int = add(2, 3)
    res := add(2, 3)    //调用函数, 定义一个变量接收返回值
    fmt.Println(res)
}

//定义函数
func add(a, b int) int {
    return a + b
}

 2.4 有多个参数,多个返回值

package main

import "fmt"

func main() {
    res, ret := add(2, 3) //调用函数, 定义多个变量接收返回值
    fmt.Println(res, ret)
}

//定义函数
func add(a, b int) (int, int) {
    return a + b, a * b
}

2.5 空白符

_ 在 Go 中被用作空白符,可以用作表示任何类型的任何值。

我们继续以 上例 函数为例,该函数返回两个值。假使我们只需要计算和的结果,该怎么调用这个函数呢?这时,空白符 _ 就上场了。

下面的程序我们只用到了函数的一个返回值 res

package main

import "fmt"

func main() {
    res, _ := add(2, 3) //调用函数, 定义多个变量接收返回值
    fmt.Println(res)
    //fmt.Println(_)  go中_代表忽略,什么都不是,它不能作为变量名,打印即报错,python中下划线可以打印并且有值
}

//定义函数
func add(a, b int) (int, int) {
    return a + b, a * b
}

2.5 命名返回值(不推荐使用)

从函数中可以返回一个命名值。一旦命名了返回值,可以认为这些值在函数第一行就被声明为变量了。

package main

import "fmt"

func main() {
	res, ret := add(2, 3) //调用函数, 定义多个变量接收返回值
	fmt.Println(res, ret)
}

//定义函数
//func add(a, b int) (int, int) {
//    c := a + b
//    d := a * b
//    return c, d
//}

func add(a, b int) (c, d int) {
    c = a + b
    d = a * b  //直接赋值,不需要再定义c,d
    return     //不需要明确指定返回值,默认返回 c, d 的值
}

请注意, 函数中的 return 语句没有显式返回任何值。由于 c 和 d 在函数声明中指定为返回值, 因此当遇到 return 语句时, 它们将自动从函数返回。 

 

3 函数的高级使用

在python和go语言中,函数是一等公民,可以把函数赋值给变量,也可以把函数作为其它函数的参数或者返回值。

函数在编译型语言中,没有先定义后调用这种说法。

3.1 匿名函数(头等函数):定义在函数内部的函数,不能是有名函数

只定义函数,相当于定义了一个变量,没有使用,编辑器会报错,因此后面加括号调用

package main

func main() {
    func (){
       //函数体代码
    }()  
}

 定义一个变量a,并把匿名函数赋值给变量a,此时变量a就是一个函数

package main

func main() {
    a := func (){
       //函数体代码
    }
    a()
}

定义一个变量a,类型为函数类型(完全定义中,变量名后面不管跟的是什么,都属于类型),把匿名函数赋值给变量a,并调用a

package main

import "fmt"

func main() {
    var a func()
    a = func() {
        fmt.Println("我是匿名函数")
    }
    a()
}

 3.2 函数返回值为函数

package main

import "fmt"

func main() {
    res := test()    //调用test函数,并把返回值赋值给变量res
    fmt.Println(res) //因为返回值是一个函数,打印为函数内存地址
    res()            //调用返回值函数
}

func test() func() {  //返回值类型是函数类型 func()
    return func() {
        fmt.Println("我是返回的函数")
    }
}

上例输出结果为:

0xa55200
我是返回的函数

3.3 函数返回值为函数,返回的函数带参数

注意:类型只要有不一样的地方,就不是同一个类型,不是同一个类型就不能相互赋值,相互运算;下例中,test函数返回值类型是函数类型,但返回的函数有参数,因此类型需要统一。

package main

import "fmt"

func main() {
    res := test() //调用test函数,并把返回值赋值给变量res
    res("nb")     //调用返回值函数,并传入参数
}

func test() func(msg string) { //func(msg string)和func()不是一个类型,如同int和int8不是一个类型
    return func(msg string) {
        fmt.Println(msg)
	}
}

3.4  函数返回值为函数,返回的函数带参数,并且带返回值

package main

import "fmt"

func main() {
    var res func(a, b int) int //定义变量res,类型为func(a, b int) int,即test函数返回值类型
    res = test()               //把test函数调用结果,即返回值赋值给变量res
    //res := test()
    fmt.Println(res)
    fmt.Println(res(2, 3))
}

func test() func(a, b int) int { //func(a, b int) int 是test函数返回值类型
    return func(a, b int) int { //返回的函数有a,b两个参数,类型为int;返回值是int类型
        return a + b
	}
}

上例输出结果为:

0x5d5260
5

3.5 函数返回值为函数,返回的函数带参数,并且带多个返回值;函数本身有参数,参数类型为函数类型

package main

import "fmt"

func main() {
    f := func() {
        fmt.Println("我是函数参数f")
    }
    //test(f)  调用test函数,传入参数f,返回函数内存地址,并没有执行f(),没有任何输出
    f1 := test(f)
    a, b := f1(2, 3)   //调用f1函数,传入两个参数,执行f(),把返回值赋值给a和b
    fmt.Println(a, b)  //最后打印变量a、b
}

//test函数带有参数f,类型是函数类型
func test(f func()) func(a, b int) (int, int) { //func(a, b int) (int, int) 是test函数返回值类型
    return func(a, b int) (int, int) { //返回的函数有a,b两个参数,类型为int;两个返回值都是int类型
        f() //f既然是函数,可以调用
        return a + b, a * b
    }
}

上例输出结果为:

我是函数参数f
5 6

上例简化写法,调用test传入一个函数作为参数-->返回值是一个函数,继续传入两个参数调用-->返回两个值,用变量接收-->最后打印

package main

import "fmt"

func main() {
    a, b := test(func() {
        fmt.Println("我是函数参数f")
    })(2, 3)
    fmt.Println(a, b)
}

//test函数带有参数f,类型是函数类型
func test(f func()) func(a, b int) (int, int) { //func(a, b int) (int, int) 是test函数返回值类型
    return func(a, b int) (int, int) { //返回的函数有a,b两个参数,类型为int;两个返回值都是int类型
        f() //f既然是函数,可以调用
        return a + b, a * b
	}
}

3.6 闭包函数

闭包函数满足两个条件:1 定义在函数内部  2 对外部作用域有引用
闭包函数就是多了一种函数传参的方法,从外部把参数包进去

装饰器是闭包函数的典型应用。go中没有装饰器的语法糖,但可以通过闭包实现装饰器

package main

import "fmt"

func main() {
    a := test(18)
    a() //a是闭包函数,执行闭包函数
}

func test(age int) func() {
    a := func() {
        fmt.Println(age)
    }
    return a
}

 

4 类型重命名

有的函数类型包含了参数和返回值类型,很长,为了方便调用,可以为类型重命名(起别名),重命名后,他们就是两种类型

package main

import "fmt"

type MyFunc func(a, b int) (int, string) //为类型重命名为 MyFunc

func main() {
    var a MyFunc = test() //调用时用别名更方便
    c, d := a(2, 3)
    fmt.Println(c, d)
}

func test() MyFunc { //test函数的返回值类型应该是 func(a,b int)(int,string),重命名为 MyFunc
    return func(a, b int) (int, string) {
        fmt.Println("nb")
        return 10, "ok"
    }
}

 

posted @ 2022-11-13 15:07  不会钓鱼的猫  阅读(323)  评论(0编辑  收藏  举报