go语言学习(三)

1.参数,返回值

2.递归函数

3.回调函数

4.匿名函数

5.闭包

6.defer使用

7.变量作用域

8.timer,ticker,和异常处理

一、函数的定义

package main
 
import "fmt"
import "strconv"
 
//无参无返回值方法
func test_1() {
    fmt.Println("调用test_1方法")
}
 
//有参无返回值方法
func test_2(s string) {
    fmt.Println("调用test_2方法")
}
 
//无参有返回值方法
func test_3() string {
    return "调用test_3方法"
}
 
//有参有返回值方法
func add(a, b int) int {
    return a + b
}
 
//不定参数
func test_4(args ...int) {
    for index, data := range args {
        fmt.Printf("args 中第%d个数是:%d\n", index, data)
    }
}
 
//取出不定参数中的第i个数
func test_5(i int, args ...int) string {
    return "args 中第" + strconv.Itoa(i) + "个数是:" + strconv.Itoa(args[i])
}
 
func main() {
    test_1()
    test_2("")
    fmt.Println(test_3())
    fmt.Println("1 + 1 = ", add(1, 1))
    test_4(1, 2, 3, 4, 5, 6)
    fmt.Println(test_5(1, 2, 3, 4, 5, 6))
}

打印结果为:

调用test_1方法
调用test_2方法
调用test_3方法
1 + 1 =  2
args 中第0个数是:1
args 中第1个数是:2
args 中第2个数是:3
args 中第3个数是:4
args 中第4个数是:5
args 中第5个数是:6

args 中第1个数是:3

二、递归函数

递归函数就是自己调用自己本身的函数,注意点就是函数的出口。使用递归函数可以节省代码使程序看上去简洁,但是函数每次调用都要重新分配内存,内存占用较大,很可能会内存溢出。

使用递归函数计算0—99的和:

package main
 
import "fmt"
 
func test(num int) int {
 
    num--
    var result int
    if num == 0 {
        result += num
        return result
    } else {
        result += test(num) + num
    }
 
    return result
}
 
func main() {
    fmt.Println(test(100))
}

三、回调函数

一个函数作为另一个函数的参数,并在函数内部调用,这个函数就是回调函数。

package main
 
import "fmt"
 
func callback(s string) {
    fmt.Println(s, "调用回调函数")
}
 
//函数可以作为参数传递,
func test(f func(string)) {
    fmt.Println("调用test方法")
    f("test")
}
 
func main() {
 
    //callback为test方法的回调函数
    //或者说是函数串联
    test(callback)
}

四、匿名函数

省略函数名的函数

package main
 
import "fmt"
 
//函数可以作为参数传递,
func test(f func(string)) {
    fmt.Println("调用test方法")
    f("test")
}
 
func main() {
 
    //此处使用匿名回调函数
    test(func(s string) {
        //函数在test函数中获取s值后再执行
        fmt.Println(s, "调用匿名回调函数")
    })
}

注意:1.匿名函数在程序中单独调用时需要在末尾加()才能被调用;

          2.匿名函数可以赋值给变量,通过变量调用;

五、闭包

一个函数作为另一个函数的返回值,这个函数称为闭包函数

package main
 
import "fmt"
 
//函数返回值是一个匿名函数
func test() func() int {
    var x int
 
    //该返回的函数为闭包函数
    return func() int {
        x++
        return x * x
    }
}
 
func main() {
 
    //将test()返回的闭包函数赋值给f
    f := test()
 
    //通过f()调用闭包函数
    fmt.Println(f())
    fmt.Println(f())
    fmt.Println(f())
    fmt.Println(f())
}

输出结果为1  4  9  16;

闭包函数的一个特性:不管函数中的变量是否超出了作用域,只要闭包函数还在使用,这些变量就还会存在。

六、defer的使用

defer关键字,后的语句会在所在函数调用完毕后执行,注意:不管函数是否报错,defer都会执行。

package main
 
import "fmt"
 
func test() {
    fmt.Println("1")
 
    //test函数调用完毕后打印“2”
    defer fmt.Println("2")
 
    fmt.Println("3")
}
 
func main() {
 
    test()
 
    fmt.Println("4")
 
    //main函数调用完毕后打印“5”
    defer fmt.Println("5")
 
    fmt.Println("6")
}

程序的执行结果为1 3 2 4 6 5.因为defer的特性,可以用来关闭输入输出流等。

七、作用域

局部变量,在函数体内部声明的变量,或是循环体内声明的变量,局部变量的生命周期依赖于它所在的函数体或循环体。

全局变量,是在go文件中与main函数同级声明的变量,它的生命周期与主程序相同。

局部变量的作用域是它所在的函数或循环体内,全局变量的作用域是在整个程序中。

八、timer,ticker,和异常处理

1.timer是一个延时器函数,使程序延时一段时间后执行。ticker是一个定时器,执行一次后,ticker会继续阻塞。

timer和ticker实际上是一个channel,go语言通过通信实现同步,

package main
 
import "fmt"
import "time"
 
func main() {
 
    //NewTimer创建一个Timer,它会在规定时间段后到期,向其自身的C字段发送当时的时间。
    timer := time.NewTimer(time.Second * 2)
 
    for {
        //C字段中没有数据会一直阻塞
        t := <-timer.C
        fmt.Println(t)
    }
}

程序在2s后打印当前时间,然后报错:fatal error: all goroutines are asleep - deadlock!

因为timer在执行完一次之后不会再向C中写数据,程序会一直阻塞在  <-timer.C 所以报死锁。

而将上面程序中的timer换做ticker:

package main
 
import "fmt"
import "time"
 
func main() {
 
    ticker := time.NewTicker(time.Second * 2)
 
    for {
        t := <-ticker.C
        fmt.Println(t)
    }
}

程序会每隔2s打印一次当前时间。

2.go语言异常处理,首先创建一个error:

package main
 
import (
    "errors"
    "fmt"
)
 
func main() {
    err := errors.New("使用字符串创建一个错误,返回error")
    fmt.Println(err)
}

error主要作为函数返回值使用,捕获函数执行中的错误。

panic函数,程序出现致命性错误是调用panic函数,使程序崩溃

package main
 
import "fmt"
 
func main() {
    fmt.Println("1")
 
    //显示调用panic函数使程序中断
    panic("this is panic")
 
    fmt.Println("1")
}

程序在打印一次1后遇到panic函数,导致程序中断,无法打印第二个1.

recover函数,程序在奔溃后保护程序继续执行,recover函数会返回程序崩溃的错误信息,并且recover函数只能放在defer后的函数中使用;

package main
 
import "fmt"
 
func test() {
 
    defer func() {
        fmt.Println(recover())
    }()
 
    panic("this is panic")
}
 
func main() {
    fmt.Println("1")
    test()
    fmt.Println("1")
}

test函数中显示调用panic函数导致程序中断,test调用完毕后执行defer后的匿名函数,recover又将程序恢复并打印panic函数的错误,所以打印结果为:

1
this is panic
1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值