• go函数传值、传引用以及函数作为值类型


    传值与传指针

    当我们传一个参数值到被调用函数里面时,实际上是传了这个值的一份copy, 当在被调用函数中修改参数值的时候,调用函数中相应实参不会发生任何变化,因为数值变化只作用在copy上。
    为了验证我们上面的说法,我们来看一个例子

    package main
    import "fmt"
    //简单的一个函数,实现了参数+1的操作
    func add1(a int) int {
        a = a+1 // 我们改变了a的值
        return a //返回一个新值
    }
    func main() {
        x := 3
        fmt.Println("x = ", x)  // 应该输出: "x = 3"
        x1 := add1(x)  //调用add1(x)
        fmt.Println("x+1 = ", x1) // 应该输出: "x+1 = 4"
        fmt.Println("x = ", x)    // 应该输出: "x = 3"
    }
    

    看到了吗?虽然我们调用了add1函数,并且在add1中执行a = a+1操作,但是上面例子中x变量的值没有发生变化。
    理由很简单:因为当我们调用add1的时候,add1接收的参数其实是x的copy,而不是x本身。
    那你也许会问了,如果真的需要传这个x本身,该怎么办呢?
    这就牵扯到了所谓的 指针。
    我们知道,变量在内存中是存放于一定地址上的,修改变量实际是修改变量地址处的内存。 只有add1函数知道x变量所在的地址,才能修改x变量的值。 所以我们需要将x所在地址&x传入函数,并将函数的参数的类型由int改为*int, 即改为指针类型,才能在函数中修改x变量的值。此时参数仍然是按copy传递的,只是copy的是一个指针。 请看下面的例子

    package main
    import "fmt"
        //简单的一个函数,实现了参数+1的操作
    func add1(a *int) int { // 请注意,
        *a = *a+1 // 修改了a的值
        return *a // 返回新值
    }
    func main() {
        x := 3
        fmt.Println("x = ", x)  // 应该输出: "x = 3"
        x1 := add1(&x)  // 调用 add1(&x) 传x的地址
        fmt.Println("x+1 = ", x1) // 应该输出: "x+1 = 4"
        fmt.Println("x = ", x)    // 应该输出: "x = 4"
    }
    

    这样,我们就达到了修改x的目的。那么到底传指针有什么好处呢?
    • 传指针使得多个函数能操作同一个对象。
    • 传指针比较轻量级 (8bytes),只是传内存地址,我们可以用指针传递体积大的结构体。 如果用参数值传递的话, 在每次copy上面就会花费相对较多的系统开销(内存和时间)。 所以当你要传递大的结构体的时候,用指针是一个明智的选择。
    • Go语言中string,slice,map这三种类型的实现机制类似指针,所以可以直接传递,而不用取地址后传递指针。 (注:若函数需改变slice的长度,则仍需要取地址传递指针)

    函数作为值类型

    在Go中函数也是一种变量,我们可以通过type来定义它,它的类型就是所有拥有相同的参数,相同的返回值的一种类型
    type typeName func(input1 inputType1 , input2 inputType2 [, ...]) (result1 resultType1 [, ...])
    函数作为类型到底有什么好处呢?那就是可以把这个类型的函数当做值来传递,请看下面的例子

    
    package main
    import "fmt"
    type testInt func(int) bool // 声明了一个函数类型
    func isOdd(integer int) bool {
        if integer % 2 == 0 {
            return false
        }
        return true
    }
    func isEven(integer int) bool {
        if integer % 2 == 0 {
            return true
        }
        return false
    }
    // 声明的函数类型在这个地方当做了一个参数
    func filter(slice []int, f testInt) []int {
        var result []int
        for _, value := range slice {
            if f(value) {
                result = append(result, value)
            }
        }
        return result
    }
    func main(){
        slice := []int {1, 2, 3, 4, 5, 7}
        fmt.Println("slice = ", slice)
        odd := filter(slice, isOdd)    // 函数当做值来传递了
        fmt.Println("Odd elements of slice are: ", odd)
        even := filter(slice, isEven)  // 函数当做值来传递了
        fmt.Println("Even elements of slice are: ", even)
    }
    

    函数当做值和类型在我们写一些通用接口的时候非常有用,通过上面例子我们看到testInt这个类型是一个函数类型, 然后两个filter函数的参数和返回值与testInt类型是一样的,但是我们可以实现很多种的逻辑, 这样使得我们的程序变得非常的灵活。

  • 相关阅读:
    matlab矩阵和矩阵操作基础
    [ZZ] MathType转化为LaTeX公式语言
    [综] 粒子滤波
    [综] Endnote怎么下载杂志格式?
    英语句子的连接方式
    [zz] postscript打印机以及ps文件转eps文件
    [zz]SCI投稿经验
    all, whole, entire, total, complete
    [转] 动态规划 最短路径
    [zz] Dynamic Time Warping 动态时间规整(弯折)
  • 原文地址:https://www.cnblogs.com/frankltf/p/13879028.html
Copyright © 2020-2023  润新知