Go中常见的错误指针

时间:2016-04-14 23:07:46

标签: pointers go

我很久没有使用指针了,当我这样做的时候只是在学术环境中,而且由于C#/ Java / scala,我现在有点生疏了。

人们在Golang中使用指针犯了哪些常见错误?

如果您正确使用它们,是否有测试方法?我想在出现问题之前总是很难检测到内存泄漏。

2 个答案:

答案 0 :(得分:3)

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

nil指针仍在那里。取消引用它们会引起恐慌,这有点像C#/ Java中的异常 - 你会得到一个清晰的错误描述和堆栈跟踪。

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

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

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

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

答案 1 :(得分:0)

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

每个切片,贴图,界面都是指针。当你有一个包含另一个包含指针的结构的结构时,你可能只看到S1{s2: S2},你认为像这样复制一个结构是很好的:a=b,当它实际上并不好时,就像s2里面一样一个poiner vatriable,让我们说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函数来创建克隆对象。您通过频道发送克隆,不再在发送方使用它。