我有這個代碼
package main
import "fmt"
type Foo struct {
Bar string
}
func (f *Foo) level4() {
fmt.Printf("Bar = %s\n", f.Bar)
}
func (f *Foo) level3() {
f.level4() // panics here, 2 levels down
}
func (f *Foo) level2() {
f.level3()
}
func (f *Foo) level1() {
f.level2()
}
type FooWrapper struct {
foo *Foo
}
func main() {
w := FooWrapper{}
w.foo.level1() // expected it to panic here, since foo is nil
}
正如預期的那樣,運行這個給出
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x47f454]
但是,我希望 nil 指標取消參考發生在w.foo.level1(),因為foo是nil。相反,它呼叫級別 1、2 和 3 并在那里發生恐慌。為什么會這樣?
游樂場鏈接
uj5u.com熱心網友回復:
為什么會這樣?
因為 w.foo.level1() 是有效陳述句,類似地 f.level2()、f.level3()、f.level4() 也是有效陳述句。
試試這個
func (f *Foo) level1() {
println("Hello Go")
f.level2()
}
它將列印Hello Go和呼叫f.level2(),還可以看到最后一次呼叫級別 4
func (f *Foo) level4() {
println("Hello Go 4")
fmt.Printf("Bar = %s\n", f.Bar)
}
它會列印Hello Go 4但在下一行發生恐慌它顯示了跟蹤或者你可以說錯誤的來源
uj5u.com熱心網友回復:
任何指標型別的默認值都是nil。
當您使用
w := FooWrapper{}
的值foo將被賦予默認值nil。
要解決該問題,您應該為 傳遞一個值foo。
w := FooWrapper{foo: &Foo{Bar: "bar"}}
為了防止這個問題,我通常會做一些建構式。
func NewFooWrapper() *FooWrapper {
return &FooWrapper{foo: &Foo{Bar: "bar"}}
}
w := NewFooWrapper()
或者萬一foo不能硬編碼的值。
func NewFooWrapper(foo *Foo) *FooWrapper {
return &FooWrapper{foo: foo}
}
w := NewFooWrapper(&Foo{Bar: "bar"})
從編碼的角度來看,這使得它更加明確,可以防止在其他代碼位置出現這些錯誤。
uj5u.com熱心網友回復:
您沒有FooWrapper正確初始化主函式中的 。你foo與型別欄位*Foo是nil里面w的變數型別FooWrapper,因為你沒有分配到指標型別變數的值,默認值是nil在Go
簡單正確的初始化如下
w := FooWrapper{
foo: &Foo{
Bar: "bar",
},
}
在操場上奔跑
輸出 :
Bar = bar
之所以說慌不進來level1(),level2(),level3()是因為他們沒有使用任何Foo這些功能中的各個領域。而且level4()發生恐慌不是因為函式呼叫,而是因為它f.Bar在列印中使用。
在圍棋中,
如果介面本身內部的具體值是 nil,則將使用 nil 接收器呼叫該方法。
您可以在https://go.dev/tour/methods/12 中找到一個簡單的示例
你也可以在呼叫下的 Go 規范檔案中找到一個很好的解釋
如果(的型別)x 的方法集包含 m 并且引數串列可以分配給 m 的引數串列,則方法呼叫 xm() 是有效的。如果 x 是可尋址的并且 &x 的方法集包含 m,則 xm() 是 (&x).m() 的簡寫
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/393704.html
上一篇:資料存盤事務-達到物體寫入限制
下一篇:C#中的@相當于Go中的變數嗎?
