• 学习函数式编程、可变参数及 defer - GO语言从入门到实战


    函数是⼀等公⺠、学习函数式编程、可变参数及 defer - GO语言从入门到实战

    函数是⼀等公⺠、学习函数式编程、可变参数及 defer

    函数是⼀等公⺠

    在Go语言中,函数可以分配给一个变量,可以作为函数的参数,也可以作为函数的返回值。这样的行为就可以理解为函数属于一等公民。

    与其他主要编程语⾔的差异

    1. 可以有多个返回值:与其他一些编程语言不同,Go语言中的函数可以返回多个值。这使得函数可以更有效地处理和传递多个结果。例如,你可以使用两个变量来接收函数的两个返回值。
    package fn_test
    
    import (
    	"fmt"
    )
    func divideAndRemainder(dividend, divisor int) (int, int) {
        quotient := dividend / divisor
        remainder := dividend % divisor
        return quotient, remainder
    }
    
    a, b := divideAndRemainder(10, 3)
    fmt.Println(a, b) // 输出:3 1
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    1. 所有参数都是值传递:在Go语言中,函数参数是通过值传递的。当你将一个变量作为参数传递给函数时,函数会创建该变量的一个副本,而不是直接操作原始变量。这有时会让人产生错觉,认为传递的是引用,但实际上是值传递。但是,对于切片(slice)、映射(map)和通道(channel)这样的引用类型,情况会有所不同。它们在函数间传递时会传递引用,而不是复制整个数据。这意味着如果你在函数内部修改了这些类型的参数,会影响原始变量的值。
    package fn_test
    
    import (
    	"fmt"
    )
    func modifySlice(s []int) {
        s[0] = 100
    }
    
    nums := []int{1, 2, 3, 4, 5}
    modifySlice(nums)
    fmt.Println(nums) // 输出:[100 2 3 4 5]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    1. 函数可以作为变量的值:在Go语言中,函数可以作为变量保存和使用。这使得你可以将函数作为参数传递给其他函数,或者将它们赋值给变量。这在实现高阶函数和函数式编程范式时非常有用。
    package fn_test
    
    import (
    	"fmt"
    )
    func add(a, b int) int {
        return a + b
    }
    
    addition := add // 将函数add赋值给变量addition
    fmt.Println(addition(2, 3)) // 输出:5
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    1. 函数可以作为参数和返回值:和其他编程语言一样,Go语言的函数可以作为参数传递给其他函数,也可以作为返回值返回。这种能力使得你可以在函数之间传递和返回操作,从而增强代码的模块化和复用性。

    这些特性使得Go语言的函数比其他许多编程语言更加灵活和强大。

    函数:可变参数及 defer

    可变参数

    可变参数允许我们在调用函数时传入任意数量的整数。函数的功能是将所有传入的整数相加,然后返回总和。

    package main
    
    import "fmt"
    
    func sum(ops ...int) int {
        s := 0
        for _, op := range ops {
            s += op
        }
        return s
    }
    
    func main() {
        fmt.Println(sum(1, 2, 3, 4, 5)) // 输出: 15
        fmt.Println(sum(10, 20, 30))    // 输出: 60
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在上述例子中,sum函数被调用了两次,每次都传入了一些整数。第一次传入的整数是1, 2, 3, 4, 5,总和是15;第二次传入的整数是10, 20, 30,总和是60。

    defer 函数

    defer语句可以用来释放资源、关闭文件、打印日志等,它具有很高的灵活性,是Go语言中常用的编程技巧之一。使用defer语句需要注意以下几点:

    1. defer语句必须放在函数内部;
    2. 多个defer语句的执行顺序是与其压入栈中的顺序相反的;
    3. defer语句中的变量在执行时会被记录下来,而不是在执行时读取;
    4. defer语句中的函数会在执行时被调用,而不是在压入栈时调用。
    package main
    
    import "testing"
    
    func TestDefer(t *testing.T) {
        t.Log("Started")
        defer func() {
            t.Log("Clear resources")
        }()
        // 其他测试代码
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    defer语句位于TestDefer函数的末尾,当这个函数执行结束时,defer语句中的函数将会被执行,打印出"Clear resources"。

    下面提供函数应用的代码案例:

    package fn_test
    
    import (
    	"fmt"
    	"math/rand"
    	"testing"
    	"time"
    )
    //函数会生成两个随机数,一个在0到9之间,一个在0到19之间。
    func returnMultiValues() (int, int) {
    	return rand.Intn(10), rand.Intn(20)
    }
    
    //函数接受一个函数作为参数,返回一个新的函数。新函数会计算传入函数的运行时间,并打印出来。
    func timeSpent(inner func(op int) int) func(op int) int {
    	return func(n int) int {
    		start := time.Now()
    		ret := inner(n)
    		fmt.Println("time spent:", time.Since(start).Seconds())
    		return ret
    	}
    }
    
    //函数会让程序暂停1秒,然后返回传入的运算。
    func slowFun(op int) int {
    	time.Sleep(time.Second * 1)
    	return op
    }
    
    //首先调用returnMultiValues函数并打印结果,然后创建了一个新的函数tsSF,它内部调用了slowFun并打印其运行时间,最后调用tsSF函数并打印结果。
    func TestFn(t *testing.T) {
    	a, _ := returnMultiValues()
    	t.Log(a)
    	tsSF := timeSpent(slowFun)
    	t.Log(tsSF(10))
    }
    
    //函数接收任意数量的整数参数,并返回它们的和。
    func Sum(ops ...int) int {
    	ret := 0
    	for _, op := range ops {
    		ret += op
    	}
    	return ret
    }
    
    //函数调用了Sum函数两次,分别传入4个和5个整数,并打印结果。
    func TestVarParam(t *testing.T) {
    	t.Log(Sum(1, 2, 3, 4))
    	t.Log(Sum(1, 2, 3, 4, 5))
    }
    
    //函数打印"Clear resources."。
    func Clear() {
    	fmt.Println("Clear resources.")
    }
    
    //首先打印"Start",然后触发一个panic,最后执行defer Clear(),清除资源。
    func TestDefer(t *testing.T) {
    	defer Clear()
    	fmt.Println("Start")
    	panic("err")	//panic是一种用于处理程序错误和异常情况的机制,类似于其他语言的异常
    }
    
    
    • 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
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    学习Go语言主要是多练,多找些代码段写写,不懂可以私聊咨询。
    码字不易,如果该文章有用,请多多关注或者赞赏,谢谢!

    欢迎关注云尔Websites CSDN博客

  • 相关阅读:
    Java学习--File
    工地木模板多少钱一张?
    Django笔记十一之外键查询优化select_related和prefetch_related
    13.cuBLAS开发指南中文版--cuBLAS中的Level-1函数copy()和dot()
    postgreSQL 系统表
    端口,域名,协议。
    在浏览器地址栏键入URL按下回车之后会经历什么?
    SSL error when connecting to the Jack server. Try ‘jack-diagnose‘
    6.29日刷题题解
    Vue---vue3的setup函数的使用
  • 原文地址:https://blog.csdn.net/wuchengzeng/article/details/133780675