3 回答

TA貢獻(xiàn)1835條經(jīng)驗 獲得超7個贊
這取決于方法接收者和變量的類型。
簡短回答:如果您正在使用該database/sql包,您的延遲Rows.Close()方法將正確關(guān)閉您的兩個Rows實例,因為Rows.Close()有指針接收器并且因為DB.Query()返回一個指針(rows也是一個指針)。請參閱下面的推理和解釋。
為避免混淆,我建議使用不同的變量,并且很清楚您想要什么以及將關(guān)閉什么:
rows := Query(`SELECT FROM whatever`)
defer rows.Close()
// ...
rows2 := Query(`SELECT FROM whatever`)
defer rows2.Close()
我想指出一個重要的事實,它來自延遲函數(shù)及其參數(shù)被立即評估,這在Effective Go博客文章和語言規(guī)范:延遲語句中也有說明:
每次執(zhí)行“defer”語句時,函數(shù)值和調(diào)用的參數(shù)都會像往常一樣評估并重新保存,但不會調(diào)用實際的函數(shù)。相反,在周圍函數(shù)返回之前立即調(diào)用延遲函數(shù),以與延遲相反的順序調(diào)用。
如果變量不是指針:當(dāng)調(diào)用延遲的方法時,您將觀察到不同的結(jié)果,這取決于該方法是否具有指針接收器。
如果變量是一個指針,您將始終看到“期望”的結(jié)果。
看這個例子:
type X struct {
S string
}
func (x X) Close() {
fmt.Println("Value-Closing", x.S)
}
func (x *X) CloseP() {
fmt.Println("Pointer-Closing", x.S)
}
func main() {
x := X{"Value-X First"}
defer x.Close()
x = X{"Value-X Second"}
defer x.Close()
x2 := X{"Value-X2 First"}
defer x2.CloseP()
x2 = X{"Value-X2 Second"}
defer x2.CloseP()
xp := &X{"Pointer-X First"}
defer xp.Close()
xp = &X{"Pointer-X Second"}
defer xp.Close()
xp2 := &X{"Pointer-X2 First"}
defer xp2.CloseP()
xp2 = &X{"Pointer-X2 Second"}
defer xp2.CloseP()
}
輸出:
Pointer-Closing Pointer-X2 Second
Pointer-Closing Pointer-X2 First
Value-Closing Pointer-X Second
Value-Closing Pointer-X First
Pointer-Closing Value-X2 Second
Pointer-Closing Value-X2 Second
Value-Closing Value-X Second
Value-Closing Value-X First
在Go Playground上試一試。
使用指針變量的結(jié)果總是好的(如預(yù)期的那樣)。
使用非指針變量和指針接收器,我們會看到相同的打印結(jié)果(最新的),但如果我們有值接收器,它會打印 2 個不同的結(jié)果。
非指針變量說明:
如前所述,包括接收器在內(nèi)的延遲函數(shù)在defer執(zhí)行時被評估。如果是指針接收器,它將是局部變量的地址。因此,當(dāng)您為其分配一個新值并調(diào)用 another 時defer,指針接收器將再次使用本地變量的相同地址(只是指向的值不同)。所以稍后在執(zhí)行函數(shù)時,兩者都會使用相同的地址兩次,但指向的值將相同,即稍后分配的值。
在值接收器的情況下,接收器是執(zhí)行時創(chuàng)建的副本defer,因此如果您為變量分配一個新值并調(diào)用 another defer,則會創(chuàng)建另一個與前一個不同的副本。

TA貢獻(xiàn)1858條經(jīng)驗 獲得超8個贊
有效的圍棋提到:
延遲函數(shù)的參數(shù)(如果函數(shù)是方法,則包括接收者)在延遲執(zhí)行時計算,而不是在調(diào)用執(zhí)行時計算。
除了避免擔(dān)心函數(shù)執(zhí)行時變量會改變值,這意味著單個延遲調(diào)用站點可以延遲多個函數(shù)執(zhí)行
在您的情況下,延遲將引用第二行實例。
這兩個延遲函數(shù)以 LIFO 順序執(zhí)行(也如“延遲、恐慌和恢復(fù)”中所述)。
正如icza在他的回答和評論中提到的:
2 個延遲
Close()
方法將引用2 個不同的 Rows 值,并且兩者都將被正確關(guān)閉,因為rows
是指針,而不是值類型。
- 3 回答
- 0 關(guān)注
- 315 瀏覽
添加回答
舉報