2 回答
TA贡献1895条经验 获得超3个赞
鉴于 Go 是垃圾收集的并且不允许指针算术,因此您可以做错的事情并不多。您可以unsafe为此使用包,但它的名称不言而喻 - 它是不安全的。
nil指针还在。取消引用它们会导致恐慌,这有点像 C#/Java 中的异常——你会得到一个清晰的错误描述和它发生的堆栈跟踪。
内存泄漏 - GC 几乎可以为您做所有事情,就像在 C#/Java 中一样。但是我知道有一个特殊情况 - 切片。删除一个元素通常是通过像这样创建另一个切片来完成的:
a = append(a[:i], a[i+1:]...)
此代码可能会泄漏您删除的元素。那是因为在内部 slice 是一个包含数组(只是一个指针)、长度和容量的结构体。当您删除一个元素时,新切片可能包含相同的数组,它仍然会引用您删除的元素。GC 不会释放它。要解决这个问题,您需要在删除元素之前将其归零。
并且还有指针与值方法接收器的混淆。这不是错误,更像是您必须做出和理解的设计决策。带有值接收器的方法将获得接收器的副本,它不能修改状态。所以如果你想修改状态,那么你需要指针接收器。此外,如果您的结构很大并且您不希望每次调用方法时都复制它们,您可能还想使用指针接收器。
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 函数来创建克隆对象。您通过您的频道发送克隆,并且不再在发送方使用它。
- 2 回答
- 0 关注
- 289 浏览
添加回答
举报
