教程 > Go 教程 > Go 高级 阅读:180

Go 语言指针与函数

指针作为函数的参数

package main

import (  
    "fmt"
)

func change(val *int) {  
    *val = 55
}
func main() {  
    a := 58
    fmt.Println("变量 a 在调用函数之前:",a)
    b := &a
    change(b)
    fmt.Println("变量 a 在调用函数之后:", a)
}

运行示例

上述代码执行结果如下

变量 a 在调用函数之前: 58
变量 a 在调用函数之后: 55

在上面的程序中,我们将a 的地址保存到指针变量 b 中,并将b传递给函数change。在change函数内部,更改 a 的值。因为指针是指向的内存地址,因此函数内部的修改会反应到函数外部的变量中。


从函数中返回指针

函数返回局部变量的指针是完全合法的。Go 编译器足够智能,它会在堆上分配这个变量。

package main

import (  
    "fmt"
)

func hello() *int {  
    i := 5
    return &i
}
func main() {  
    d := hello()
    fmt.Println("变量 d 的值为:", *d)
}

运行示例

上述代码执行结果如下

变量 d 的值为: 5

在上面的程序中,我们从函数hello()中返回局部变量 i 的地址。对于Go语言来说,编译器会进行转义分析,如果发现函数返回的是指针,则会忽略局部作用域,在堆上给i分配空间。

上面代码中的方式在 C 和 C++ 等编程语言中是有问题的,因为i一旦从函数hello()返回,变量就会超出范围。

不要将指向数组的指针作为参数传递给函数。

假设我们想对函数内的数组进行一些修改,并且对函数内该数组所做的更改应该对调用者可见。这样做的一种方法是将指向数组的指针作为参数传递给函数。

package main

import (  
    "fmt"
)

func modify(arr *[3]int) {  
    (*arr)[0] = 90
}

func main() {  
    a := [3]int{89, 90, 91}
    modify(&a)
    fmt.Println(a)
}

我们将数组 a 的地址传递给modify()函数。在 modify 函数中,我们引用数组的第一个元素,给其赋值90。因此上面程序的输出是 [90 90 91]

a[x] 是 (*a)[x] 的简写。所以上面程序中的 (*arr)[0] 可以替换为 arr[0]。让我们使用这种速记语法重写上面程序中的 modify 函数。

func modify(arr *[3]int) {  
   arr[0] = 90
}

程序还是输出 [90 90 91]

尽管这种将指向数组的指针作为参数传递给函数并对其进行修改的方式有效,但这并不是 Go 中实现此目的的惯用方式。我们可以使用切片

让我们使用slices重写上面的程序。

package main

import (  
    "fmt"
)

func modify(sls []int) {  
    sls[0] = 90
}

func main() {  
    a := [3]int{89, 90, 91}
    modify(a[:])
    fmt.Println(a)
}

运行示例

上述代码执行结果如下

[90 90 91]

上面这段代码更简洁,而且是经常食用的 Go的编程方式 :)。因此,忘记将指向数组的指针当作函数的参数来传递的方式吧。

查看笔记

扫码一下
查看教程更方便