Go-理解并使用 Go 指针

本节重点:

  • 理解并使用 Go 指针

在本节中,我们将学习指针在 Go 中是如何工作的,我们还将了解 Go 指针与其他语言(如 C 和 C++)中的指针有何不同。

概念

指针是存储另一个变量的内存地址的变量。

![[Pasted image 20220802230857.png]]

在上图中,变量 b 的值是 156,存储在地址为 0x1040a124的内存中。变量 a 存储了变量 b 的地址。现在可以说 a 指向 b

指针的声明

指向类型 T 的指针用 *T 表示。
让我们编写一个声明指针的程序。

package main
 
import (  
    "fmt"
)
 
func main() {  
    b := 255
    var a *int = &b
    fmt.Printf("Type of a is %T\n", a)
    fmt.Println("address of b is", a)
}

& 操作符用来获取一个变量的地址。在上面的程序中,第 9 行我们将 b 的地址赋给 a(a 的类型为 *int)。现在我们说 a指向了 b。当我们打印 a 的值时,b 的地址将会被打印出来。程序的输出为:

Type of a is *int  
address of b is 0x1040a124  

你可能得到的是一个不同的 b 的地址,因为 b 可以在内存中的任何地方。

指针的空值

指针的零值为nil

package main
 
import (  
    "fmt"
)
 
func main() {  
    a := 25
    var b *int
    if b == nil {
        fmt.Println("b is", b)
        b = &a
        fmt.Println("b after initialization is", b)
    }
}

b 在上述程序中最初为 nil,然后分配给 a 的地址。该程序输出

b is <nil>  
b after initialisation is 0x1040a124

使用新函数创建指针

Go 还提供了一个方便的函数new来创建指针。该new函数将一个类型作为参数并返回一个指针,该指针指向作为参数传递的类型的新分配的空值。
下面的例子可以说明清楚。

package main
 
import (  
    "fmt"
)
 
func main() {  
    size := new(int)
    fmt.Printf("Size value is %d, type is %T, address is %v\n", *size, size, size)
    *size = 85
    fmt.Println("New size value is", *size)
}

在上面的程序中,在第8行。我们使用new函数来创建类型的int指针。该函数将返回一个指向新分配的int类型的零值指针。int类型的零值为0. 因此 size 将是 *int类型并将指向0, *size将为0。
上面的程序将打印

Size value is 0, type is *int, address is 0x414020  
New size value is 85

指针解引用

解引用指针的意思是通过指针访问被指向的值。指针 a 的解引用表示为:*a
让我们看看这在程序中是如何工作的。

package main  
import (  
    "fmt"
)
 
func main() {  
    b := 255
    a := &b
    fmt.Println("address of b is", a)
    fmt.Println("value of b is", *a)
}

在上面程序的第 10 行,我们将 a 解引用,并打印了它的值。不出所料,它会打印出 b 的值。程序会输出:

address of b is 0x1040a124  
value of b is 255 

让我们再编写一个程序,用指针来修改 b 的值。

package main
 
import (  
    "fmt"
)
 
func main() {  
    b := 255
    a := &b
    fmt.Println("address of b is", a)
    fmt.Println("value of b is", *a)
    *a++
    fmt.Println("new value of b is", b)
}

在上面程序的第 12 行中,我们把 a指向的值加 1,由于 a 指向了 b,因此 b 的值也发生了同样的改变。于是 b 的值变为 256。程序会输出:

address of b is 0x1040a124  
value of b is 255  
new value of b is 256 

向函数传递指针参数

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

package main
 
import (  
    "fmt"
)
 
func hello() *int {  
    i := 5
    return &i
}
func main() {  
    d := hello()
    fmt.Println("Value of d", *d)
}

上面程序的第9行,我们从hello函数中返回局部变量的地址i。此代码的行为在 C 和 C++ 等编程语言中是未定义的,因为一旦函数返回,变量i就会超出范围。但是在 Go 的情况下,编译器会进行转义分析,并·在地址转义本地范围时在堆上进行分配。因此,该程序将起作用并打印:Value of d 5

Go 不支持指针运算

Go 不支持其他语言(如 C 和 C++)中存在的指针算法。

package main
 
func main() {  
    b := [...]int{109, 110, 111}
    p := &b
    p++
}

上述程序会抛出编译错误main.go:6: invalid operation: p++ (non-numeric type *[3]int)

注意:

  • 不要向函数传递数组的指针,而应该使用切片。你可以试着验证下为什么?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极简网络科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值