簡體   English   中英

返回(可能被遮蔽)變量的慣用方法,這些變量已被定義為單獨的多變量返回的一部分

[英]Idiomatic way to return (potentially shadowed) variables which have been defined as part of a separate multiple variable return

正常情況

在編寫具有命名返回值的函數時,通常可以使用裸返回(無論您是否應該單獨討論)。 它們可能類似於以下內容:

func add(x, y int) (z int) {
    z = x + y
    return
}

return此處與return z相同

問題情況

但是下面的刪節片段......

func loadModule(moduleName, fileRoot string) (module []byte) {
    if strings.HasSuffix(moduleName, ".md") {
        module, err := readConvertMDFile(fileRoot + "htdocs/md/" + moduleName)
        if err != nil {
            log.Println(err)
        }
        return module
    } else {
        module = []byte{}
        return
    }
}

(這個片段運行正常,是我目前解決問題的方法)

...編譯器會抱怨module is shadowed如果不是return module ,則只return 這是因為module是與err一起聲明的(第二次),必須聲明它在此范圍內尚不存在。

可能的解決方案

  1. 像我一樣做並明確命名返回變量。 雖然這不是一個可怕的解決方案,但我覺得應該有一種方法來安排代碼,以便它以裸露的回報運行。 其他人評論說 ,這種明確的回報導致了“代碼味”。

  2. 在開頭添加var err error並使用多個賦值而不是聲明。 可能是一個更好的解決方案,但我更願意在可能的情況下使用隱式賦值以保持一致性並減少不必要的行。

  3. 使用臨時的moduleT變量然后分配module = moduleT ...這只是感覺凌亂和多余。

雖然我可以得到我正在尋找的編譯結果,但我希望有人可以建議一種明確的,慣用的寫作方式。

我總是使用你建議的解決方案2 - 添加一個額外的var語句。

func loadModule(moduleName, fileRoot string) (module []byte) {
    var err error
    if strings.HasSuffix(moduleName, ".md") {
        module, err = readConvertMDFile(fileRoot + "htdocs/md/" + moduleName)
        if err != nil {
            log.Println(err)
        }
        return
    } else {
        // no need for this as module will be nil if it isn't written to
        // a nil slice is perfectly legal and has len()=0
        // and can be appended to etc
        // module = []byte{}
        return
    }
}

選項2也是最有效的解決方案。 請記住,go返回堆棧上的所有值,因此命名的返回值等於堆棧分配的變量。

如果在選項1或選項3中沒有裸返回,那么無論如何都有一個隱含的module = modulemodule = moduleT語句。

不幸的是,變量陰影會在一段時間后咬住每個Go程序員。 我非常喜歡編譯器禁止函數中的所有陰影,因為它是真正的bug的來源。

在我寫這個問題時,我的功能如下所示:

(顯示主要是為了證明其詳細程度)

func loadModule(moduleName, fileRoot string) (module []byte) {
    if strings.HasSuffix(moduleName, ".md") {
        module, err := readConvertMDFile(fileRoot + "htdocs/md/" + moduleName)
        if err != nil {
            log.Println(err)
        }
        return module
    } else if strings.HasSuffix(moduleName, ".html") {
        module, err := ioutil.ReadFile(fileRoot + "htdocs/html/" + moduleName)
        if err != nil {
            log.Println(err)
        }
        return module
    } else if strings.HasSuffix(moduleName, ".js") {
        module, err := ioutil.ReadFile(fileRoot + "htdocs/js/" + moduleName)
        if err != nil {
            log.Println(err)
        }
        return module
    } else if strings.HasSuffix(moduleName, ".css") {
        module, err := ioutil.ReadFile(fileRoot + "htdocs/css/" + moduleName)
        if err != nil {
            log.Println(err)
        }
        return module
    } else {
        module = []byte{}
        return
    }
}

這使用我建議的解決方案1.它有很多重復的代碼(我仍然是一個初學者)。 如果我通過將var err error放在then函數的頂部來改為使用建議的解決方案2(但不是我最初想到的方式),則代碼會以兩種方式得到改進:

func loadModule(moduleName, fileRoot string) (module []byte) {
    var err error
    switch {
    case strings.HasSuffix(moduleName, ".md"):
        module, err = readConvertMDFile(fileRoot + "htdocs/md/" + moduleName)
    case strings.HasSuffix(moduleName, ".html"):
        module, err = ioutil.ReadFile(fileRoot + "htdocs/html/" + moduleName)
    case strings.HasSuffix(moduleName, ".js"):
        module, err = ioutil.ReadFile(fileRoot + "htdocs/js/" + moduleName)
    case strings.HasSuffix(moduleName, ".css"):
        module, err = ioutil.ReadFile(fileRoot + "htdocs/css/" + moduleName)
    default:
        module = []byte{}
    }
    if err != nil {
            log.Println(err)
        }
    return
}

不再有陰影變量,錯誤記錄和返回都可以移出每個if語句,從而產生更清晰的代碼。

可能有一種方法可以改善這一點。 編輯:...然后,在@ANisus的建議下,if-else鏈已被替換為switch語句。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM