【问题标题】:Why is interface pointer assignment so hard?为什么接口指针赋值这么难?
【发布时间】:2021-10-13 22:09:54
【问题描述】:

我正在尝试重构一些golang源代码,我想使用接口但是我发现了很大的困难(请耐心等待,我是一个铁杆C/C++孤儿)

我提取了一个小样本,显示我得到的错误

package main

import "fmt"

type LogProcessor interface {
    Init() int
}

type MyProcessor struct {
    a int
}

func (m MyProcessor) Init() int {
    return m.a
}

func main() {
    t := &(MyProcessor{2})
    var p *LogProcessor = &(MyProcessor{4}) //!!!fails!!!
    fmt.Println((*t).Init(), (*p).Init())
}

为什么第二个作业失败了?


添加修改后的代码以演示我正在尝试做的事情。我认为接口更类似于 C++ 类。我的错。还在学习中

package main

import "fmt"

type LogProcessor interface {
    Init() int
}

type MyProcessor struct {
    a int
}

func (m *MyProcessor) Init() int {
    m.a++
    return m.a
}

func main() {
    t := &(MyProcessor{2})
    m := MyProcessor{4}
    var p LogProcessor = &m
    fmt.Println(t.Init(), p.Init())
    fmt.Println(t.a, m.a)
}

【问题讨论】:

  • Go 中几乎从不使用指向接口的指针,因此 p 应该只是 LogProcessor。你也不需要(*t).Init(),只需t.Init(),让编译器自动转换为(*t).Init()即可。
  • 在这两种语言方面更有经验的人希望能回答您。但是你有这些资源来帮助你转换 github.com/golang/go/wiki/GoForCPPProgrammerstalks.golang.org/2012/goforc.slide#1(你编写 Go 代码的方式是铁杆;)
  • @aturetta 是的,但没关系,几乎总是如此。接口指针唯一有意义的情况是,如果您使用间接分配接口变量。除此之外,接口按值传递并不重要。您对按值传递有哪些具体担忧?
  • @aturetta 您将向结构传递一个指针,并确保它使用指针接收器而不是值接收器来实现接口。
  • @aturetta 顺便说一句,如果您必须使用指向接口的指针,则需要分两步进行初始化play.golang.org/p/MAg0N3xD-6F

标签: go pointers interface


【解决方案1】:

它失败了,因为您使用的是指向接口的指针,如果您删除指向 LogProcessor for var p 的指针,它可以工作

package main

import "fmt"

type LogProcessor interface {
    Init() int
}

type MyProcessor struct {
    a int
}

func (m MyProcessor) Init() int {
    return 2
}

func main() {
    t := &(MyProcessor{2})
    var p LogProcessor = MyProcessor{4} // works without a pointer to  the interface type
    fmt.Println((*t).Init(), (p).Init())
}

【讨论】:

    【解决方案2】:

    表达式MyProcessor{2}composite literal。获取复合文字的地址是有效的,它的类型为*MyProcessor

    所以这里:

    t := &(MyProcessor{2})
    

    t 的类型将是 *MyProcessor

    你的失败路线:

    var p *LogProcessor = &(MyProcessor{4}) //!!!fails!!!
    

    右侧表达式的类型又是*MyProcessor。它是一个具体类型的指针。 p 的类型是*LogProcessor,它是一个指向另一个类型的指针。 Assignability 规则不适用于此处,因此该值根本无法分配给变量 p

    请注意,有一个可分配性规则:

    如果以下条件之一适用,则值 x 可分配给 T 类型的 variable(“x 可分配给 T”):

    在您的示例中,p 的类型不是接口类型,而是指向接口的指针。你很少(如果有的话)需要这个。

    如果你使用“just”接口类型:

    var p LogProcessor = &(MyProcessor{4}) // This works!
    

    这是因为具体类型*MyProcessor 实现了接口类型LogProcessor。你也不需要括号,你可以简单地使用&MyProcessor{4}

    那么你当然不能取消引用p(因为它不是指针),所以你必须使用p.Init()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-17
      • 1970-01-01
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-10
      相关资源
      最近更新 更多