golang接口地址和接口区别

Posted

技术标签:

【中文标题】golang接口地址和接口区别【英文标题】:golang address of interface and interface difference 【发布时间】:2019-02-03 07:01:23 【问题描述】:

我发现了很多类似的问题,但不是我想要的 请看下面的代码。

(1)

var buf bytes.Buffer
fmt.Fprint(&buf,"test")

(2)

var w http.ResponseWriter
http.Error(w,http.StatusText(http.StatusBadRequest),http.StatusBadRequest)

http.ResponseWriter 和 bytes.Buffer 都实现了 io.Writer 接口,所以我认为它们应该具有相同的行为。

当我换成

http.Error(&w,http.StatusText(http.StatusBadRequest),http.StatusBadRequest)

jetbrains goland 告诉我

Cannot use '&w' (type *http.ResponseWriter) as type ResponseWriter

我想知道为什么 buf 有 '&' 可以工作,但另一个不工作?

我google了一下,有人说传值给函数的时候可以参考&w

但另一个说如果你传递一个指针,它可以尊重值

来自https://github.com/golang/go/wiki/MethodSets#variables

为了更容易记住这些规则,将指针和值接收器方法与方法集分开考虑可能会有所帮助。在任何已经是指针或可以获取其地址的东西上调用指针值方法是合法的(如上例中的情况)。对任何值或可以取消引用的值调用值方法是合法的(任何指针的情况都是如此;这种情况在规范中明确指定)。

我完全糊涂了,我自己无法理解。 希望您能帮帮我,谢谢!

【问题讨论】:

bytes.Buffer 是具体类型,http.ResponseWriter 是接口类型。关于方法的指针/值接收器的注释是无关的。 函数http.Error 需要一个http.ResponseWriter,但你传递的是一个*http.ResponseWriter(如错误所示)。这是函数参数(不是方法接收器)的错误类型。 如果您看到func Error(w ResponseWriter, error string, code int) 的定义,它需要ResponseWriter 而不是指向它的指针。这是错误背后的原因,而不是您正在考虑的原因。 你真的应该深入研究 Go 的类型系统。这不是神奇地或随机地将 & 和 * 放在东西之前。您必须了解不同的类型,例如结构类型 (bytes.Buffer) 和接口类型 (http.ResponseWriter),并了解方法集。所以不是得到这个答案的正确地方。你可以试试 reddit 或 golang-nuts。 两者都是io.Writers,是的,但两者都不是 http.ResponseWriters。 【参考方案1】:

也许我可以尝试更详细地解释所有非常优秀的 cmets 已经在说什么:

接口(大部分)是 go 中的指针

如果另一种类型实现了接口定义的所有方法,则 go 中的接口被实现(满足)。通常这是通过在类型的指针上添加方法来完成的,不是直接类型。

type SomeInterface interface 
    SomeMethod string


type SomeStruct struct  // often is a struct but does not have to be

// a method on the structs pointer
func (s *SomeStruct) SomeMethod string 
    return ""

这个结果:

    SomeStruct 没有实现 SomeInterface,*SomeStruct 有! 接口(通常)已经是一个指针。

你的例子

var b bytes.Buffer
fmt.Fprintf(&b, "some text")

var w http.ResponseWriter
http.Error(w, "some error", 1)

bytes.Buffer 类型的变量bstruct,从源代码中可以看到:

type Buffer struct 
    buf       []byte   // contents are the bytes buf[off : len(buf)]
    off       int      // read at &buf[off], write at &buf[len(buf)]
    bootstrap [64]byte // memory to hold first slice; helps small buffers avoid allocation.
    lastRead  readOp   // last read operation, so that Unread* can work correctly.

    // FIXME: it would be advisable to align Buffer to cachelines to avoid false
    // sharing.

如果你想将它用作类型 io.Writer(接口),你需要得到一个 bytes.Buffer 的指针,因为(通常)指针方法在 go 中使用:fmt.Fprintf(&b, "some text")

http.ResponseWriter 类型的变量winterface

type ResponseWriter interface 
    Header() Header
    Write([]byte) (int, error)
    WriteHeader(statusCode int)

由于接口(通常)已经是一些底层实现的指针,我们可以在不使用指针的情况下使用它:http.Error(w, "some error", 1)

接口初始化

接口本身不能被初始化和使用!你总是需要一个结构或其他类型来实现接口,然后你可以初始化它并将其用作类型SomeInterface。 例如here is the implementation of gin 代表http.ResponseWriter。从代码中可以看出,它的方法使用指针接收器。所以 http.ResponseWriter 已经是一个指向结构体的指针了。

免责声明

这只是尝试使这个复杂主题听起来简单的一种方法(希望如此)。这不是技术上完整或完全准确的解释。尽量保持简单但尽可能准确。

【讨论】:

以上是关于golang接口地址和接口区别的主要内容,如果未能解决你的问题,请参考以下文章

Golang basic_leaming 指针类型和值类型实现接口的区别以及接口嵌套

Golang basic_leaming接口

Golang basic_leaming接口

如何判断Golang接口是否实现?

golang的reflect

golang reflect反射(一):interface接口的入门(大白话)