索引:https://waterflow.link/articles/1666019023270
在 Go 中,在塊中宣告的變數名可以在內部塊中重新宣告, 這種稱為變數陰影的原理很容易出現常見錯誤,
以下示例顯示了由于變數陰影而導致的意外副作用, 它以兩種不同的方式獲取課件資訊,根據printLog這個布林值,判斷是否列印日志而走到不同的代碼分支:
package main
import "fmt"
type Courseware struct {
Id int64
Name string
Code string
}
func main() {
printLog := false
var courseware *Courseware // 1
if printLog {
courseware , err := getCoursewareAndLog() // 2
if err != nil {
fmt.Println("get courseware err: ", err)
}
fmt.Println(courseware) // 3
} else {
courseware, err := getCourseware() // 2
if err != nil {
fmt.Println("get courseware err: ", err)
}
fmt.Println(courseware) // 3
}
fmt.Println(courseware) // 4
}
func getCoursewareAndLog() (*Courseware, error) {
fmt.Println("列印日志,,,")
return &Courseware{
Id: 1,
Name: "多媒體課件",
Code: "CW100",
}, nil
}
func getCourseware() (*Courseware, error) {
return &Courseware{
Id: 2,
Name: "多媒體課件1",
Code: "CW101",
}, nil
}
我們可以分析下上面的代碼:
- 首先我們定義了一個courseware變數,初始化為指向Courseware的指標,默認為nil
- 我們在if代碼塊的內部呼叫了獲取課件詳情的方法,并回傳Courseware的指標和error,我們仍然使用變數courseware去接收,注意這里我們使用了短變數宣告的操作
:=,說明在代碼塊內部我們重新宣告了一個變數courseware,這個并不是外部的courseware變數, - 我們在代碼塊內部列印下獲取課件詳情的資訊
- 我們在在if代碼塊外部列印下獲取課件詳情的資訊
如果現在我們用的是PHP語言,那這個絕對不會出現任何問題,if代碼塊內部會列印出獲取課件的詳情,外部也會列印出獲取課件的詳情,對應上面代碼中的3、4,畢竟PHP是世界上最好的語言么,
但是在上面的結果中,3會正常列印課件詳情,4會列印if代碼塊外部的courseware,所以是nil,
我們看下列印的結果:
go run 1.go
&{2 多媒體課件1 CW101}
<nil>
這就是所謂的變數陰影,
那我們該如何修改上面的代碼使程式變得正常呢?
其實有2種方式修改:
-
增加一個臨時變數
package main import "fmt" type Courseware struct { Id int64 Name string Code string } func main() { printLog := false var courseware *Courseware // 1 if printLog { cw , err := getCoursewareAndLog() // 2 courseware = cw // 增加臨時變數 if err != nil { fmt.Println("get courseware err: ", err) } fmt.Println(courseware) // 3 } else { cw, err := getCourseware() // 2 courseware = cw // 增加臨時變數 if err != nil { fmt.Println("get courseware err: ", err) } fmt.Println(courseware) // 3 } fmt.Println(courseware) // 4 } func getCoursewareAndLog() (*Courseware, error) { fmt.Println("列印日志,,,") return &Courseware{ Id: 1, Name: "多媒體課件", Code: "CW100", }, nil } func getCourseware() (*Courseware, error) { return &Courseware{ Id: 2, Name: "多媒體課件1", Code: "CW101", }, nil }看下列印結果,正常輸出:
go run 1.go &{2 多媒體課件1 CW101} &{2 多媒體課件1 CW101} -
不使用:=,err在外部初始化
package main import "fmt" type Courseware struct { Id int64 Name string Code string } func main() { printLog := false var courseware *Courseware // 1 var err error // err放到外層 if printLog { courseware , err = getCoursewareAndLog() // 2 =號賦值 if err != nil { fmt.Println("get courseware err: ", err) } fmt.Println(courseware) // 3 } else { courseware, err = getCourseware() // 2 =號賦值 if err != nil { fmt.Println("get courseware err: ", err) } fmt.Println(courseware) // 3 } fmt.Println(courseware) // 4 } func getCoursewareAndLog() (*Courseware, error) { fmt.Println("列印日志,,,") return &Courseware{ Id: 1, Name: "多媒體課件", Code: "CW100", }, nil } func getCourseware() (*Courseware, error) { return &Courseware{ Id: 2, Name: "多媒體課件1", Code: "CW101", }, nil }看下結果,正常輸出:
go run 1.go &{2 多媒體課件1 CW101} &{2 多媒體課件1 CW101}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/518794.html
標籤:Go
上一篇:這個定時任務,我從3min優化到200ms。老板,我盡力了!
下一篇:瑞吉外賣實戰專案全攻略——第三天
