go語言函數參數傳遞中的指針變量陷阱:為何函數內修改外部變量無效?
本文分析一個Go語言程序中關于指針變量賦值的常見問題。程序嘗試在函數內部修改指向數據庫連接對象的指針變量,但主函數中該變量卻未被修改。
以下代碼片段展示了這個問題:
var db *sql.DB func main() { initDB(db) fmt.Println(db) // 打印 <nil> } func initDB(db *sql.DB) { var err error db, err = sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/data") checkErr(err) db.SetMaxOpenConns(100) db.SetMaxIdleConns(100) db.SetConnMaxLifetime(time.Minute * 3) if err := db.Ping(); err != nil { checkErr(err) } fmt.Println(db) // 這里打印的是正確的值 } func checkErr(err error) { if err != nil { panic(err) } }
main 函數打印的 db 仍然是 nil,而 initDB 函數內部已成功連接數據庫。這是因為 Go 語言的函數參數傳遞機制是值傳遞。即使參數是指針類型,傳遞的也是指針值的副本。
立即學習“go語言免費學習筆記(深入)”;
在 initDB 函數中,db, err := sql.Open(…) 創建了一個新的 *sql.DB 對象,并將該對象賦值給 initDB 函數內部的局部變量 db。這并沒有修改 main 函數中 db 變量的指向。initDB 函數結束后,其局部變量 db 被銷毀,main 函數中的 db 仍然是 nil。
要正確修改 main 函數中的 db 變量,需要使用指針的指針,或者在 initDB 函數中使用指針接收器。 以下是如何使用指針的指針來解決這個問題:
var db *sql.DB func main() { initDB(&db) fmt.Println(db) // 現在將打印正確的值 } func initDB(db **sql.DB) { var err error *db, err = sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/data") checkErr(err) (*db).SetMaxOpenConns(100) (*db).SetMaxIdleConns(100) (*db).SetConnMaxLifetime(time.Minute * 3) if err := (*db).Ping(); err != nil { checkErr(err) } fmt.Println(*db) // 這里打印的是正確的值 } func checkErr(err error) { if err != nil { panic(err) } }
通過傳遞 db 的地址 (&db),initDB 函數可以直接修改 main 函數中 db 變量的指向。
? 版權聲明
文章版權歸作者所有,未經允許請勿轉載。
THE END
喜歡就支持一下吧
相關推薦