2 回答

TA貢獻(xiàn)1895條經(jīng)驗(yàn) 獲得超3個(gè)贊
鑒于 Go 是垃圾收集的并且不允許指針?biāo)阈g(shù),因此您可以做錯(cuò)的事情并不多。您可以unsafe
為此使用包,但它的名稱不言而喻 - 它是不安全的。
nil
指針還在。取消引用它們會(huì)導(dǎo)致恐慌,這有點(diǎn)像 C#/Java 中的異?!銜?huì)得到一個(gè)清晰的錯(cuò)誤描述和它發(fā)生的堆棧跟蹤。
內(nèi)存泄漏 - GC 幾乎可以為您做所有事情,就像在 C#/Java 中一樣。但是我知道有一個(gè)特殊情況 - 切片。刪除一個(gè)元素通常是通過像這樣創(chuàng)建另一個(gè)切片來完成的:
a = append(a[:i], a[i+1:]...)
此代碼可能會(huì)泄漏您刪除的元素。那是因?yàn)樵趦?nèi)部 slice 是一個(gè)包含數(shù)組(只是一個(gè)指針)、長度和容量的結(jié)構(gòu)體。當(dāng)您刪除一個(gè)元素時(shí),新切片可能包含相同的數(shù)組,它仍然會(huì)引用您刪除的元素。GC 不會(huì)釋放它。要解決這個(gè)問題,您需要在刪除元素之前將其歸零。
并且還有指針與值方法接收器的混淆。這不是錯(cuò)誤,更像是您必須做出和理解的設(shè)計(jì)決策。帶有值接收器的方法將獲得接收器的副本,它不能修改狀態(tài)。所以如果你想修改狀態(tài),那么你需要指針接收器。此外,如果您的結(jié)構(gòu)很大并且您不希望每次調(diào)用方法時(shí)都復(fù)制它們,您可能還想使用指針接收器。

TA貢獻(xiàn)1998條經(jīng)驗(yàn) 獲得超6個(gè)贊
我發(fā)現(xiàn)的常見錯(cuò)誤是人們忘記了復(fù)雜結(jié)構(gòu)中的指針。
每個(gè) slice、map、interface 都是一個(gè)指針。當(dāng)您有一個(gè)包含另一個(gè)包含指針的結(jié)構(gòu)的結(jié)構(gòu)時(shí),您可能會(huì)看到S1{s2: S2},并且您認(rèn)為這樣復(fù)制結(jié)構(gòu)很好:a=b當(dāng)實(shí)際上它不好時(shí),如在 s2 內(nèi)部,一個(gè)指針變量,比方說p,會(huì)有他們的地址被復(fù)制,而不是它指向的值。當(dāng) yoy 修改在 *a.s2.p 處找到的值時(shí),*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
這是一個(gè)非常簡單的示例,看起來很明顯存在問題,但在更大的應(yīng)用程序中,這可能不那么明顯。
頻道也會(huì)出現(xiàn)此問題。如果您發(fā)送一個(gè)指針,您將在另一端獲得相同的指針(指針值的副本,這是一個(gè)地址)。在這種情況下,與第一種情況一樣,安全的解決方案是使用 Clone 函數(shù)來創(chuàng)建克隆對(duì)象。您通過您的頻道發(fā)送克隆,并且不再在發(fā)送方使用它。
- 2 回答
- 0 關(guān)注
- 212 瀏覽
添加回答
舉報(bào)