全局 space 中的 Nil 指针异常
Nil Pointer Exception in Global space
我正在尝试理解指针的概念。
我有三个包main、models和controller
在我的models.go
type Database struct {
config string
port int
}
var DB *Database
func GetDatabase() *Database {
fmt.Println("Reporting from Models.")
DB = &Database{config: "This is stunning!", port: 3306}
fmt.Printf("%v, %T\n", DB, DB)
return DB
}
在controller.go
var DB *models.Database = models.DB
func GetController() {
fmt.Println("Reporting from Controllers!")
fmt.Printf("%v, %T\n", DB, DB)
}
在main.go
var DB *models.Database
func main() {
DB = models.GetDatabase()
controllers.GetController()
fmt.Println("REporting from main")
fmt.Printf("%v, %T\n", DB, DB)
}
输出
Reporting from Models.
&{This is stunning! 3306}, *models.Database
Reporting from Controllers!
<nil>, *models.Database
REporting from main
&{This is stunning! 3306}, *models.Database
我的问题是为什么我的 DB 控制器中会出现 nil
?我的直觉是它在模型内部的包级别访问全局 DB 变量,这是 nil
因为它没有启动。但是既然它是一个引用,我正试图在我的 GetDatabase 函数中给它一个正确的引用,为什么当我尝试访问我的控制器中的那个变量时,这个变化没有得到反映?
如果你想分享一些东西,你需要一个指针,但不是 nil
指针,一个实际分配的指针。然后你还需要使用解引用来更新共享指针的每个实例,基本上解引用是你如何更新存储在指针指向的地址的数据。
var DB = &Database{}
func GetDatabase() *Database {
// an asterisk before an expression is how you dereference a pointer
*DB = Database{config: "This is stunning!", port: 3306}
}
var DB = models.DB
func GetController() {
fmt.Printf("%v, %T\n", DB, DB) // not nil anymore
}
var DB = models.DB
func main() {
// you can ommit the assignment since GetDatabase() updates the shared
// pointer of models.DB
_ = models.GetDatabase()
fmt.Println(DB)
}
指针本质上是整数,它们存储的数字是内存中某个其他变量的地址。如果您不习惯指针,但来自一种具有数组的语言,那么将指针视为保存数组索引的整数或多或少是正确的,其中数组是内存。
当你运行这样的陈述时,这个....
package controllers
var DB *models.Database = models.DB
你在这里真正做的是有效的整数赋值,其中 models.DB
的值按值复制到变量 controllers.DB
中。在这行代码执行的时间点,models.DB
的值为nil
,所以你把地址nil
复制到controllers.DB
.
在按值复制之后,对 models.DB
变量的任何更改都与 controllers.DB
变量完全分离。它们是两个不同的东西,它们都指向 nil
。现在,当您将某个实际 DB
实例的地址分配给 models.DB
时,models.DB
的值发生变化,但不相关的变量 controllers.DB
不受影响。
对一个变量的更改(即赋值)不会反映到其他变量。但是,如果两个指针指向同一个内存,并且您更改了内存本身,那么通过两个指针都可以看到更改。
如果你这样做了...
models.DB = &Database{} // non-nil address
controllers.DB = models.DB // non-nil address is copied
那么两个变量将包含相同的地址,并且对它们现在指向的单个 Database
变量的更改将通过两个指针可见。但是,重新分配变量本身,即models.DB = nil
,不会影响其他变量。
回到数组示例,您已经有效地做到了这一点:
arr := []string{"zero", "one", "two", "three"}
idx1 := 0 // ie models.DB
idx2 := 0 // ie controllers.DB
idx1 = idx2 // copy 0 by value into idx1
idx2 = 1 // does not affect idx1, which is still 0
arr[idx1] // "zero"
arr[idx2] // "one"
我正在尝试理解指针的概念。
我有三个包main、models和controller
在我的models.go
type Database struct {
config string
port int
}
var DB *Database
func GetDatabase() *Database {
fmt.Println("Reporting from Models.")
DB = &Database{config: "This is stunning!", port: 3306}
fmt.Printf("%v, %T\n", DB, DB)
return DB
}
在controller.go
var DB *models.Database = models.DB
func GetController() {
fmt.Println("Reporting from Controllers!")
fmt.Printf("%v, %T\n", DB, DB)
}
在main.go
var DB *models.Database
func main() {
DB = models.GetDatabase()
controllers.GetController()
fmt.Println("REporting from main")
fmt.Printf("%v, %T\n", DB, DB)
}
输出
Reporting from Models.
&{This is stunning! 3306}, *models.Database
Reporting from Controllers!
<nil>, *models.Database
REporting from main
&{This is stunning! 3306}, *models.Database
我的问题是为什么我的 DB 控制器中会出现 nil
?我的直觉是它在模型内部的包级别访问全局 DB 变量,这是 nil
因为它没有启动。但是既然它是一个引用,我正试图在我的 GetDatabase 函数中给它一个正确的引用,为什么当我尝试访问我的控制器中的那个变量时,这个变化没有得到反映?
如果你想分享一些东西,你需要一个指针,但不是 nil
指针,一个实际分配的指针。然后你还需要使用解引用来更新共享指针的每个实例,基本上解引用是你如何更新存储在指针指向的地址的数据。
var DB = &Database{}
func GetDatabase() *Database {
// an asterisk before an expression is how you dereference a pointer
*DB = Database{config: "This is stunning!", port: 3306}
}
var DB = models.DB
func GetController() {
fmt.Printf("%v, %T\n", DB, DB) // not nil anymore
}
var DB = models.DB
func main() {
// you can ommit the assignment since GetDatabase() updates the shared
// pointer of models.DB
_ = models.GetDatabase()
fmt.Println(DB)
}
指针本质上是整数,它们存储的数字是内存中某个其他变量的地址。如果您不习惯指针,但来自一种具有数组的语言,那么将指针视为保存数组索引的整数或多或少是正确的,其中数组是内存。
当你运行这样的陈述时,这个....
package controllers
var DB *models.Database = models.DB
你在这里真正做的是有效的整数赋值,其中 models.DB
的值按值复制到变量 controllers.DB
中。在这行代码执行的时间点,models.DB
的值为nil
,所以你把地址nil
复制到controllers.DB
.
在按值复制之后,对 models.DB
变量的任何更改都与 controllers.DB
变量完全分离。它们是两个不同的东西,它们都指向 nil
。现在,当您将某个实际 DB
实例的地址分配给 models.DB
时,models.DB
的值发生变化,但不相关的变量 controllers.DB
不受影响。
对一个变量的更改(即赋值)不会反映到其他变量。但是,如果两个指针指向同一个内存,并且您更改了内存本身,那么通过两个指针都可以看到更改。
如果你这样做了...
models.DB = &Database{} // non-nil address
controllers.DB = models.DB // non-nil address is copied
那么两个变量将包含相同的地址,并且对它们现在指向的单个 Database
变量的更改将通过两个指针可见。但是,重新分配变量本身,即models.DB = nil
,不会影响其他变量。
回到数组示例,您已经有效地做到了这一点:
arr := []string{"zero", "one", "two", "three"}
idx1 := 0 // ie models.DB
idx2 := 0 // ie controllers.DB
idx1 = idx2 // copy 0 by value into idx1
idx2 = 1 // does not affect idx1, which is still 0
arr[idx1] // "zero"
arr[idx2] // "one"