2016-04-14 40 views
0

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

人们在Golang中使用指针会犯什么常见错误?

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

+1

Go仍然收集垃圾。你必须担心的唯一事情就是在必要的情况下正确解除引用。编译器会检查这个隐含的原因,如果它有错,就会导致不兼容的类型。另一件容易让人们操心的是方法上的指针与值接收器。如果你的接收者是一个值,那么它被传递给方法,如果它是一个指针,那么它是通过引用完成的,所以如果你想修改它接收的方法中的对象的状态,那么确保你使用了一个指针。 – evanmcdonnal

回答

3

鉴于Go是垃圾收集,不允许指针算术,因此没有太多可以做错的事情。你可以使用unsafe软件包,但它的名字可以说明问题 - 这是不安全的。

nil指针仍然存在。解引用它们会导致恐慌,这在C#/ Java中有点像例外 - 你会得到一个清晰的错误描述和一个堆栈跟踪。内存泄漏 - GC将为您做几乎所有的事情,就像在C#/ Java中一样。但有一个特殊情况,我知道 - 切片。删除元素通常是通过建立这样的另一片做:

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

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

而且还有指针vs值方法的接收者混淆。这不是一个错误,更像是一个你必须做出和理解的设计决定。带值接收方法会得到接收方的副本,它不能修改状态。所以如果你想修改状态,那么你需要指针接收器。同样,如果你的结构很大,并且你不希望它们在你每次调用方法的时候都被复制,你也可能需要使用指针接收器。

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

这是一个很简单的例子,它看起来明显有问题,但更大的应用程序,这可能不是那么明显。

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