为了账号安全,请及时绑定邮箱和手机立即绑定

Go中指针的常见错误

Go中指针的常见错误

Go
MMTTMM 2022-01-04 14:05:06
我已经很长时间没有使用指针了,当我使用指针时,它只是在学术环境中使用,多亏了 C#/Java/scala,我现在有点生疏了。人们在 Golang 中使用指针会犯哪些常见错误?有没有测试你是否正确使用它们的方法?我想在出现问题之前总是很难检测到内存泄漏。
查看完整描述

2 回答

?
蛊毒传说

TA贡献1895条经验 获得超3个赞

鉴于 Go 是垃圾收集的并且不允许指针算术,因此您可以做错的事情并不多。您可以unsafe为此使用包,但它的名称不言而喻 - 它是不安全的。

nil指针还在。取消引用它们会导致恐慌,这有点像 C#/Java 中的异常——你会得到一个清晰的错误描述和它发生的堆栈跟踪。

内存泄漏 - GC 几乎可以为您做所有事情,就像在 C#/Java 中一样。但是我知道有一个特殊情况 - 切片。删除一个元素通常是通过像这样创建另一个切片来完成的:

a = append(a[:i], a[i+1:]...)

此代码可能会泄漏您删除的元素。那是因为在内部 slice 是一个包含数组(只是一个指针)、长度和容量的结构体。当您删除一个元素时,新切片可能包含相同的数组,它仍然会引用您删除的元素。GC 不会释放它。要解决这个问题,您需要在删除元素之前将其归零。

并且还有指针与值方法接收器的混淆。这不是错误,更像是您必须做出和理解的设计决策。带有值接收器的方法将获得接收器的副本,它不能修改状态。所以如果你想修改状态,那么你需要指针接收器。此外,如果您的结构很大并且您不希望每次调用方法时都复制它们,您可能还想使用指针接收器。


查看完整回答
反对 回复 2022-01-04
?
米琪卡哇伊

TA贡献1998条经验 获得超6个赞

我发现的常见错误是人们忘记了复杂结构中的指针。


每个 slice、map、interface 都是一个指针。当您有一个包含另一个包含指针的结构的结构时,您可能会看到S1{s2: S2},并且您认为这样复制结构很好:a=b当实际上它不好时,如在 s2 内部,一个指针变量,比方说p,会有他们的地址被复制,而不是它指向的值。当 yoy 修改在 *a.s2.p 处找到的值时,*b.s2.p 将返回相同的值。


package main


import (

    "fmt"

)


type S1 struct {

    v int

    s2 S2

}


type S2 struct {

    p *int

}


func main() {

    x := 1

    b := S1{v: 10, s2: S2{p: &x}}

    a := b

    fmt.Printf("a = %+v\nb = %+v\n*a.s2.p = %d\n*b.s2.p = %d\na.s2.p = %p\nb.s2.p = %p\n", a, b, *a.s2.p, *b.s2.p, a.s2.p, b.s2.p)

    *a.s2.p = 5

    fmt.Printf("*a.s2.p = %d\n*b.s2.p = %d\na.s2.p = %p\nb.s2.p = %p\n", *a.s2.p, *b.s2.p, a.s2.p, b.s2.p)

}

http://play.golang.org/p/KQ99KICgbu


这是一个非常简单的示例,看起来很明显存在问题,但在更大的应用程序中,这可能不那么明显。


频道也会出现此问题。如果您发送一个指针,您将在另一端获得相同的指针(指针值的副本,这是一个地址)。在这种情况下,与第一种情况一样,安全的解决方案是使用 Clone 函数来创建克隆对象。您通过您的频道发送克隆,并且不再在发送方使用它。


查看完整回答
反对 回复 2022-01-04
  • 2 回答
  • 0 关注
  • 289 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号