恐慌:运行时错误:接口中无效的内存地址或零指针取消引用

问题描述 投票:0回答:1

我在界面中遇到恐慌:运行时错误:无效的内存地址或零指针取消引用。尽管我尝试了各种方法和解决方案来使其发挥作用,但它们并没有像我预期的那样发挥作用。我不知道问题出在哪里。

这是我收到的错误:

This is the directory1 function
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x47ae8a]

goroutine 1 [running]:
github.com/ibilalkayy/test/two/directory1.MyInterfaces.CallDirectory2(...)
        /mnt/d/go/src/github.com/ibilalkayy/test/two/directory1/directory1.go:19
github.com/ibilalkayy/test/two/directory1.MyInterfaces.Directory1({{0x0?, 0x0?}})
        /mnt/d/go/src/github.com/ibilalkayy/test/two/directory1/directory1.go:15 +0x6a
main.main()
        /mnt/d/go/src/github.com/ibilalkayy/test/two/main.go:12 +0x17
exit status 2

main.go 文件

package main

import (
    "github.com/ibilalkayy/test/two/directory1"
    "github.com/ibilalkayy/test/two/directory2"
)

func main() {
    myDirectory1 := directory1.MyInterfaces{}
    myDirectory2 := directory2.MyInterfaces{}

    myDirectory1.Directory1()
    myDirectory2.Directory2()
}

interfaces.go 文件

package interfaces

type InterfaceDirectory1 interface {
    Directory1()
}

type InterfaceDirectory2 interface {
    Directory2()
}

type AllInterfaces interface {
    InterfaceDirectory1
    InterfaceDirectory2
}

目录1.go文件

package directory1

import (
    "fmt"

    "github.com/ibilalkayy/test/two/interfaces"
)

type MyInterfaces struct {
    interfaces.AllInterfaces
}

func (m MyInterfaces) Directory1() {
    fmt.Println("This is the directory1 function")
    m.CallDirectory2()
}

func (m MyInterfaces) CallDirectory2() {
    m.Directory2()
}

directory2.go 文件

package directory2

import (
    "fmt"

    "github.com/ibilalkayy/test/two/interfaces"
)

type MyInterfaces struct {
    interfaces.AllInterfaces
}

func (m MyInterfaces) CallDirectory1() {
    m.Directory1()
}

func (m MyInterfaces) Directory2() {
    m.CallDirectory1()
    fmt.Println("This is the directory2 function")
}
go dereference panic
1个回答
0
投票

是的,正如 kostix 在他们的评论中指出的那样,您的代码读起来好像围绕 golang 的接口可能存在一些混乱。其一,通常不赞成创建太大的接口,而且集中接口并不是一个好主意。在使用的地方声明您想要/需要使用的接口,不要导入包含接口的单独包,这些接口又在另一个包/模块中实现。

无论如何,恐慌的原因很简单:

type MyInterfaces struct {
    AllInterfaces
}

这声明了一个嵌入

AllInterfaces
类型的结构类型。这并不意味着您的类型“继承”接口。这并不意味着您的结构实现接口。这只是意味着它通过嵌入类型暴露/导出

当你写下:

foo := MyInterfaces{}

您将此结构类型分配给变量,但没有初始化嵌入的

AllInterfaces
类型,因此您的结构本质上将其内部字段初始化为
nil
。请注意,像这样的嵌入类型基本上意味着编写:

foo.Directory1()

相当于:

foo.AllInterfaces.Directory1()

因此,即使您已经嵌入了类型,您也必须将其视为结构中的隐含字段。如果

MyInterfaces
类型上没有冲突的名称,则任何嵌入类型导出的字段/方法都可以访问,就像它们是外部类型上的字段一样,但如果存在名称冲突,则需要指定确切的名称您想要访问的字段或方法:

type Foo struct {
    Name string
    Age  uint
}
type Bar struct {
    Name string
    Size uint
}
type Foobar struct {
    Foo
    Bar
}

fb := Foobar{}
fb.Age = 123 // fine, sets Foobar.Foo.Age
fb.Size = 10 // fine, sets Foobar.Bar.Size
fb.Name // which one? Foobar.{Foo,Bar}.Age?
// you need to be specific here...
fb.Foo.Name = "Foo name"
fb.Bar.Name = "Bar name"
// or initialise when assigning:
fb = Foobar{
    Foo: Foo{
        Name: "Foo name",
        Age:  123,
    },
    Bar: Bar{
        Name: "Bar name",
        Size: 10,
    },
}

您正在嵌入一个接口,因此与上面的示例(嵌入可以初始化的结构)不同,编译器无法将嵌入类型初始化为

nil
以外的任何类型。这意味着:

foo := MyInterfaces{}

相当于:

foo := MyInterfaces{
     AllInterfaces: nil,
}

因此,调用

foo.Directory1()
相当于
foo.AllInterfaces.Directory1()
,实际上是:
foo.AllInterfaces.InterfaceDirectory1.Directory1()
(但接口组成有点不同,所以现在我们坚持使用
foo.AllInterfaces.Directory1()

现在让我们填空:

  1. 我们知道
    foo
    已初始化为
    MyInterfaces{nil}
  2. 我们也知道
    foo.Directory1()
    相当于
    foo.AllInterfaces.Directory1()
  3. 因此
    foo.Directory1()
    本质上是
    foo.nil.Directory1()

通过调用

nil
上的方法(该方法未实现相关方法),您会遇到运行时恐慌。解决方案是通过提供
MyInterfaces
的实际实现来正确初始化
AllInterfaces

// assume svc is a type that implements AllInterfaces:
foo := MyInterfaces{
     AllInterfaces: svc,
}
foo.Directory1() // works fine

在处理嵌入类型时,尤其是接口时,提供构造函数是很常见的:

func NewMyInterfaces(all AllInterfaces) *MyInterfaces {
    return &MyInterfaces{
        AllInterfaces: all,
    }
}

这会让你的代码看起来更干净:

foo := NewMyInterfaces(svc)

如果

svc
不实现该接口,它将生成编译时错误

© www.soinside.com 2019 - 2024. All rights reserved.