附加到结构切片时无效的内存地址或 nil 指针取消引用
Posted
技术标签:
【中文标题】附加到结构切片时无效的内存地址或 nil 指针取消引用【英文标题】:Invalid memory address or nil pointer dereference when appending to slice of structs 【发布时间】:2014-02-23 18:08:51 【问题描述】:package main
import (
"fmt"
)
type Person struct
name string
func main()
p := make([]*Person, 0)
p = append(p, &Person"Brian")
fmt.Println(p[0].name)
p = append(p, &Person"Le Tu")
fmt.Println(p[1].name)
以上工作正常。
package main
import (
"fmt"
)
type Person struct
name string
func main()
p := make([]*Person, 1) //Changed to 1 instead of 0
p = append(p, &Person"Brian")
fmt.Println(p[0].name)
p = append(p, &Person"Le Tu")
fmt.Println(p[1].name)
上述恐慌。
我对@987654323@ 的理解是它隐藏了扩展/添加的机制。显然,我使用append
作为切片的一种“推动”的心理模型是不正确的。谁能向我解释为什么上面的第二个样本会出现恐慌?为什么我不能只 append
我的结构?
【问题讨论】:
【参考方案1】:Reference page for make
使用make
构建切片时,第一个整数参数是创建切片的实际长度:
p := make([]*Person, 1)
// is equivalent to
p := []*Personnil //<- slice of length 1, cells contain the default
// zero value for the *Person type
如果你想创建一个长度为 0 的切片,但具有预定义的 容量,你需要使用 make
的 3 参数版本:
p := make([]*Person, 0, 100) //<- slice of length 0, but the first 100 append
// won't reallocate the slice
关于如何使用这两种情况的简单示例:
//100-cell slice :
p1 := make([]*Person, 100)
for i := 0; i < 100; i++
name := fmt.Sprintf("Foo %d", i+1)
//you can access and assign to p1[i] because p1 has 100 cells :
p1[i] = &Personname
fmt.Printf("p1[0].Name : %s\n", p1[0].Name)
fmt.Printf("p1[99].Name : %s\n", p1[99].Name)
//0-cell, 100-capacity slice :
p2 := make([]*Person, 0, 100)
for i := 0; i < 100; i++
name := fmt.Sprintf("Foo %d", i+1)
//you cannot access p2[i], the cell doesn't exist yet :
p2 = append(p2, &Personname)
fmt.Printf("p2[0].Name : %s\n", p2[0].Name)
fmt.Printf("p2[99].Name : %s\n", p2[99].Name)
play.golang link
【讨论】:
【参考方案2】:例如,
package main
import (
"fmt"
)
type Person struct
name string
func main()
p := make([]*Person, 1) //Changed to 1 instead of 0
fmt.Println(len(p), p)
p = append(p, &Person"Brian")
fmt.Println(len(p), p)
fmt.Println(p[1].name)
fmt.Println(p[0])
fmt.Println(p[0].name)
输出:
1 [<nil>]
2 [<nil> 0x10500190]
Brian
<nil>
panic: runtime error: invalid memory address or nil pointer dereference
p
在附加前的长度为 1,在附加后的长度为 2。所以p[0]
有未初始化的指针值nil
,p[0].name
无效。
The Go Programming Language Specification
Appending to and copying slices
可变参数函数 append 将零个或多个值 x 附加到 s 的 类型 S,必须是切片类型,并返回结果切片, 也是S型。
Pointer types
未初始化的指针的值为 nil。
Selectors
以下规则适用于选择器:
4) 如果 x 是指针类型且值为 nil 且 x.f 表示结构字段,则分配或评估 x.f 会导致运行时恐慌。
【讨论】:
以上是关于附加到结构切片时无效的内存地址或 nil 指针取消引用的主要内容,如果未能解决你的问题,请参考以下文章
为啥 gorm db.First() 会因“无效的内存地址或 nil 指针取消引用”而恐慌? [复制]
无法生成 ngrokpanic:运行时错误:无效的内存地址或 nil 指针取消引用
k6:WARpanic:运行时错误:无效的内存地址或 nil 指针取消引用