接口的结构嵌入,出现紧急情况:运行时错误

时间:2019-01-28 17:08:45

标签: go struct interface go-interface

我正在尝试一个与接口的结构嵌入有关的示例

// https://talks.golang.org/2014/go4java.slide#52
// Struct embedding of interfaces
// https://play.golang.org/p/SYiZ7M1OEhU

package main

import (
    "bytes"
    "fmt"
    "net"
)

// net.Conn has Read and Write

type loopBack struct {
    net.Conn
    buf bytes.Buffer
}

func (c *loopBack) Read(b []byte) (int, error) {
    fmt.Println("loopBack Read")
    return 0, nil 
}

func main() {

    loop := loopBack{}
    loop.Read(nil)
    loop.Write(nil)                                                                           
}

并且Write方法未定义,所以出现运行时错误

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0xffffffff addr=0x0 pc=0xe28ca]

goroutine 1 [running]:
main.main()
    /tmp/sandbox812386031/main.go:28 +0x6a

在编译时是否存在某种验证方法?

链接到代码

https://play.golang.org/p/SYiZ7M1OEhU

2 个答案:

答案 0 :(得分:0)

您正在做的是 而不是说“ NaN”。
要获取有关缺少的方法以及不匹配的loopBack implements net.Conn的编译时错误,请声明Read()的类型:
(并且不要将net.Conn嵌入loop中)

loopBack

答案 1 :(得分:0)

Golang不需要 exlicit 接口实现。您在这里做什么:

type loopBack struct {
    net.Conn
    buf bytes.Buffer
}

类似于:

type loopBack struct{
    Conn net.Conn
    buf bytes.Buffer
}

net.Conn是一种接口类型,您的loopBack类型的第一个字段可以是实现net.Conn接口的任何内容,当然它要比Read和{ {1}}(see here)。

嵌入类型的优点在于,可以直接在嵌入它们的类型上访问字段和接收器函数(不包括名称冲突)。

有了嵌入式Write字段,您确实可以编写:

net.Conn

如果loop.Write(nil) 字段已初始化(否则,其值为Conn)。将声明更改为第二个版本nil无效,您必须编写:

loop.Write

类型嵌入功能非常强大,但是当您第一次入门时,会有很多陷阱。幸运的是,有一整段说明了嵌入effective go doc

无论如何,如上所述,您可以调用函数并访问字段(如果要嵌入结构类型而不是接口)。但是,有一件事:必须正确初始化字段!

这就是您出问题的地方:您仍然必须初始化 loop.Conn.Write(nil) 变量的Conn部分,否则您所做的与以下操作相同:< / p>

loopBack

这自然会导致恐慌(取消指针取消引用)...

例如:

net.Conn(nil).Write(nil)

无法设置conn, err := net.Dial("tcp", "localhost:80") if err != nil { log.Fatalf("failed to dial localhost: %+v", err) } loop := loopBack{ Conn: conn, } loop.Write(nil) // same as conn.Write(nil) 嵌入字段类似于执行以下操作:

net.Conn

切片中存在10个元素,但它们都已初始化为s := make([]*int, 10) // make slice of 10 pointers to int fmt.Println(len(s)) // outputs 10 *s[0]++ // add 1 to first element PANICS