当遍历结构体切片时,Golang内存地址问题

3

我对Go非常新手,所以可能有一个非常简单的修复方法。 我在调用数组中结构体内接口的方法时遇到了问题。 我认为最好通过一个示例来解释,这是我能够将我的代码精简到的最基本的示例:

package main

import "fmt"

/* Test Types */
type Test interface {
    Hello() string
}

type TestRecord struct {
    test Test
    name string
}

type TestList []TestRecord

/* Other Type */
type Other struct{}

func (o Other) Hello() string {
return "Hello From Other"
}

func main() {
    /* Init TestList into t */
    t := make(TestList, 1, 100)

    /* Create TestRecord and add it to the list */
    tr := TestRecord{Other{}, "OtherRecord"}
    t = append(t, tr)

    /* Loop over list and  */
    for _, otr := range t {
        fmt.Println(otr.name)
        fmt.Println(otr.test.Hello())
    }
} 

当我尝试执行此操作时,出现以下错误:
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x20 pc=0x400efd]

在这种设置中,我如何正确地通过循环数组调用Hello?
1个回答

7
您的问题出在这行代码中。
 t := make(TestList, 1, 100)

在这里,你已经将t初始化为一个包含一个TestRecord的数组,但是你没有设置该TestRecord中的任何字段,因此t[0].test为nil。你不能在nil接口上调用方法,因为Go不知道要调用哪个方法。
最简单的修复方法(对源代码更改最小)是使用以下语句从一个空的TestList开始:
t := make(TestList, 0, 100)

然而,如果你愿意,你也可以依赖于append来根据需要分配t,并通过以下方式声明将t作为nilTestList开始:

var t TestList

在你的测试程序中,我建议使用第二个版本,因为你没有充分利用容量,但我认识到你可能从实际代码中简化了这部分内容,提前指定容量确实很有帮助。


调用空值方法

  • 你可以在 nil结构体指针上调用方法,因为Go可以在编译时确定应该调用哪个函数。但是,如果该函数对结构体指针进行解引用,那么你将在解引用处遇到崩溃。
  • 当你通过接口访问此指针时,Go需要对其进行解引用以确定应该调用哪个函数,因此一旦进行函数调用,程序就会崩溃。

非常感谢!我想这是我忽略的一些简单问题。 - KayoticSully

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接