Golang 函数

创建函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package main
 
import "fmt"
 
//有参数,有返回值
func demo(a int, s string) (int, string) {
    return a * a, s + s
}
 
//有参数,没有返回值
func test(a int) {
    fmt.Println(a)
}
 
//不需要参数,有返回值
func example() string {
    return "this is a str be returned"
}
func main() {
    x := 10
    str := "bye "
    x, str = demo(x, str)
    fmt.Println(x, str) //100 bye bye
 
    y := 99
    test(y) //99
 
    //有返回值,但不接收返回值
    example()
     
    //接收返回值
    s := example()
    fmt.Println(s) //this is a str be returned
}

  

可变参数

  如果一个函数的参数个数是可变的,那么可以在定义函数时,在参数列表的最后一个参数类型之前加上...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main
 
import "fmt"
 
func sum(num ...int) int {
    res := 0
    for _, v := range num {
        res += v
    }
    return res
}
 
func multi_params(a string, x int, y ...int) {
    fmt.Println("第一个参数:", a)
    fmt.Println("第二个参数:", x)
    fmt.Println("可变参数:", y)
}
 
func main() {
    tot := sum(1, 2, 3, 4, 5)
    fmt.Println(tot) //15
     
    multi_params("hello", 99, 1, 2, 3, 4)
    //第一个参数: hello
    //第二个参数: 99
    //可变参数: [1 2 3 4]
}

  

函数多返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main
 
import "fmt"
 
//返回值可直接写返回值的类型,如果是单个返回值,可省略返回值的括号
//参数列表中,如果参数类型都相同,可以只在最后写一次类型
func swap(a, b int) (int, int) {
    return b, a
}
 
//可以指定返回值的名称,这个名称只是为了方便理解,并没有什么用
func compute(a int, b int) (sum, sub int) {
    return a + b, a - b
}
 
func main() {
    a := 10
    b := 20
    a, b = swap(a, b)
    fmt.Println(a, b) //20 10
 
    x, y := compute(10, 5)
    fmt.Println(x, y)  //15 5
}

  

错误处理 defer

  defer后面的函数在Go程序设计语言中被称为延迟函数,为什么叫延迟呢?因为这个defer函数的存在于一个函数之中(包括main函数),defer函数执行的时机是在 包含他的那个函数(上一层函数)将要执行完之前的最后一步,即函数最后一条语句执行完了,然后在执行这个defer函数,如果同一个函数内部有多个defer的函数,那么,这些个defer函数的执行顺序按照栈的后进先出,最后定义的defer函数最先执行,最先定义的defer函数最后执行。

  先看一个简单的例子:

1
2
3
4
5
6
7
8
9
10
package main
import "fmt"
func main(){
    defer func(){
        fmt.Println("run last")
    }()
    //注意defer的函数后面一定要加圆括号,不然就是定义函数,而不会执行函数
 
    fmt.Println("run first")
}

  在上面这个例子中,包含defer函数的 函数是main函数,所以在main()函数执行完毕之后(不能说main函数执行完毕,应该说已经顺序执行完除了defer函数以外的所有语句),才执行defer函数,所以运行结果如下:

1
2
run first
run last

  

然后看下面这个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main
import "fmt"
func test(){
    fmt.Println("One")
    defer func(){
        fmt.Println("two")
    }()
    defer func(){
        fmt.Println("three")
    }()
}
func main(){
    test()
    fmt.Println("run first")
}

  上面这个例子中test函数包含在main()中,test函数中包含两个延迟函数,所以正常语句执行完之后,应该先执行第二个延迟函数,然后执行第一个延迟函数,然后test函数执行完毕后,在顺序执行test函数后面的语句。

1
2
3
4
One
three
two
run first

 

  再看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main
import "fmt"
func test(){
    fmt.Println("One")
    defer func(){
        fmt.Println("two")
    }()
    defer func(){
        fmt.Println("three")
    }()
}
func main(){
    defer test()  #与上面一个例子的区别,这里test函数是延迟函数
    fmt.Println("run first")
}

  因为test函数此时作为延迟函数,那么test函数在main函数中最后执行,执行test的时候,因为test中又有延迟函数,仍旧遵守上面的顺序,所以执行的结果如下:

1
2
3
4
run first
One
three
two

  延迟函数类似于其他面向对象语言中的析构函数,只是很类似,不要混为一谈。延迟通常用来做一些收尾工作,给他的主子擦屁股,比如关闭打开的文件,或者一些连接状态,亦或者清楚一些数据。。。。。

 

defer的注意事项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main
 
import "fmt"
 
func main() {
    i := 0
    defer fmt.Println("调用defer1,i=", i)
    defer func() {
        fmt.Println("调用defere2,i=", i)
    }()
 
    for i = 0; i < 5; i++ {
        fmt.Print(" ", i)
    }
    fmt.Println()
}
 
// 0 1 2 3 4
//调用defere2,i= 5
//调用defer1,i= 0

  上面第一个defer中的i,其实是在循环开始之前,就已经将i的值传递给fmt.Println了。

  类似于下面这个写法

1
2
3
4
i := 0
defer func(x int) {
    fmt.Println("调用defer1,i=", x)
}(i)

  

函数变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main
 
import "fmt"
 
//定义新的类型,为函数类型,后面是函数签名
type handler func(int, int) int
 
func main() {
    foo := func(a, b int) (sum int) {
        return a + b
    }
    fmt.Println(foo(3, 5)) //8
 
    demo := foo
    fmt.Println(demo(3, 3)) //6
 
    var test handler
    test = demo
    fmt.Println(test(4, 4))
}

  

闭包

  即函数(外部函数)中再定义一个函数(内部函数),并且将内部函数返回,对,返回一个函数,内部函数就叫做闭包。在内部函数中可以调用外部函数中的变量。并且在外部函数调用完之后,外部函数中定义的局部变量并不会立即销毁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main
import "fmt"
//外部函数需要参数 a int,b int
//返回值为一个函数,该函数需要一个参数int型的time倍数 ,并返回一个int型的值
func demo(a, b int) func(time int) int {
    sum := a + b //求和
    return func(t int) int {
        return sum * t
    }
}
 
func main() {
    foo := demo(3, 5)
    //此时foo是一个函数
    fmt.Println(foo) //0x10936b0   指向内部函数的地址
    fmt.Println(foo(4)) //32
}

  第二个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main
 
import "fmt"
 
func demo() func() int {
    cnt := 0 
    return func() int {
        cnt++
        return cnt
    }
}
 
func main() {
    foo := demo()
    //调用demo之后,demo函数内部的局部变量并不会立即销毁,会一直保存
    fmt.Println(foo())  //1
    fmt.Println(foo())  //2
}

  

Go语言中函数的参数不支持默认值

posted @   寻觅beyond  阅读(374)  评论(0编辑  收藏  举报
编辑推荐:
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
阅读排行:
· 手把手教你更优雅的享受 DeepSeek
· AI工具推荐:领先的开源 AI 代码助手——Continue
· 探秘Transformer系列之(2)---总体架构
· V-Control:一个基于 .NET MAUI 的开箱即用的UI组件库
· 乌龟冬眠箱湿度监控系统和AI辅助建议功能的实现
返回顶部
点击右上角即可分享
微信分享提示