首頁  >  文章  >  後端開發  >  重新分配變數時動態類型未清除 - 這是一個錯誤嗎?

重新分配變數時動態類型未清除 - 這是一個錯誤嗎?

PHPz
PHPz轉載
2024-02-13 16:00:11491瀏覽

重新分配变量时动态类型未清除 - 这是一个错误吗?

php小編小新在這裡為大家解答一個常見的問題:「重新分配變數時動態類型未清除- 這是一個錯誤嗎?」在PHP中,變數的動態類型是其靈活性的重要特點。當我們重新給一個變數不同類型的值時,PHP會自動根據新的值來調整變數的類型。然而,有時候我們可能會因為忘記清除變數而導致意外的結果。那麼,這種情況算不算是個錯誤呢?讓我們一起來探討一下。

問題內容

Go 中有一個眾所周知的怪癖,即持有 nil 值的介面不等於 nil。這是因為在底層,介面是動態類型和值的組合,只有當兩者都是 nil 時,它才會是 nil。所以 (*MyStruct)(nil) != nil(nil)(nil) == nil。本部落格對此進行了更好的解釋。

我發現了一些與此行為相關的東西,這讓我感到驚訝,在這裡:https://goplay.tools/snippet/VF8oWt9XvO8。程式碼也複製如下。

看來,如果您重新指派分配了動態類型的變量,動態類型就會被記住並保留為新值。這對我來說似乎是出乎意料的,我認為重新分配變數應該覆蓋所有過去的狀態。

我檢查了語言規範,但它有點含糊:https://go.dev/ref/spec#Assignability

<code>
Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block ... Redeclaration does not introduce a new variable; it just assigns a new value to the original.
</code>

不清楚這是否僅意味著值,或值加上動態類型。

這種行為是語言中有意為之的,還是運行時重新使用記憶體進行變數重新分配而不清除所有狀態的一些副作用?

程式碼:

package main

import (
    "fmt"
)

type CustomError struct{}

func (e *CustomError) Error() string {
    return "err"
}

// ===================

func FuncThatReturnsCustomError() *CustomError {
    return nil
}

func FuncThatReturnsCustomErrorAsErrorInterface() error {
    // although the underlying returned value is nil, the return value from this func != nil
    // https://glucn.medium.com/golang-an-interface-holding-a-nil-value-is-not-nil-bb151f472cc7
    return FuncThatReturnsCustomError()
}

// ===================

func main() {
    // Assign a non-nil value to err (value is nil, dynamic type is not)
    err := FuncThatReturnsCustomErrorAsErrorInterface()
    fmt.Printf("err == nil: %v                                    false because although the value is nil, the dynamic type is not nil (expected)\n", err == nil)

    // Call func where return type is a pointer to a struct and and returns nil
    // It is nil, as expected, this call is just to provide a comparison with the call after
    newlyDeclaredErr := FuncThatReturnsCustomError()
    fmt.Printf("newlyDeclaredErr == nil: %v                        true because func returned nil (expected)\n", newlyDeclaredErr == nil)

    // Exactly the same call as above, but reusing the original err variable instead of declaring a new one
    // Back to not nil, unexpected
    err = FuncThatReturnsCustomError()
    fmt.Printf("original err reassigned == nil: %v                false presumably because err remembered its old dynamic type even after reassignment (unexpected)\n", err == nil)

    // Reassign err again, but explicitly to nil rather than by calling a function that returns nil. This time it's nil again
    err = nil
    fmt.Printf("original err after assignment to nil == nil: %v    true, expected but not consistent with the case above\n", err == nil)
}

解決方法

你「意想不到」的部分是這樣的:

err = FuncThatReturnsCustomError()

您期望結果為 nilerr 是介面類型(error)的變數,FuncThatReturnsCustomError() 的回傳類型為 *CustomError。這不是一個介面類型,而是一個具體類型(指向 CustomError 的指標)。由於它會傳回一個非介面值,因此當指派給介面類型的變數時,必須將其包裝到介面值中。這是將建立非 nil 介面值的位置。這與「記住」或「保留」舊類型資訊無關。

如果您使用具有下列介面結果類型的函數:

func returnNilErr() error {
    return nil
}

並測試它:

err = returnNilErr()
fmt.Printf("result of returnNilErr() == nil: %v\n", err == nil)

您會得到(在 Go Playground 上嘗試):

result of returnNilErr() == nil: true

因為returnNilErr()已經有介面結果型別(error),所以它的回傳值不需要打包成介面值,在賦值給err變數時可以照原樣使用。 p>

查看相關/可能的重複:隱藏 nil 值,理解為什麼 Go 在這裡失敗

Go 常見問題:為什麼我的 nil 錯誤值不等於 nil? 一个>

以上是重新分配變數時動態類型未清除 - 這是一個錯誤嗎?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除