将结构体指针分配给接口指针

huangapple go评论93阅读模式
英文:

Assign struct pointer to interface pointer

问题

我正在尝试重构一些 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)
}
英文:

I'm trying to refactor some golang source code, and I would like to use interfaces but I find huge difficulties (bear with me, I'm a hard-core C/C++ orphan)

I extracted a small sample exhibiting the error I get

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())
}

Why is the second assignment failing?


Adding the code modified to demonstrate what I was trying to do. I thought interfaces where more similar to C++ classes. My fault. Still learning

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)
}

答案1

得分: 4

表达式MyProcessor{2}是一个复合字面量。可以取复合字面量的地址,它的类型将是*MyProcessor

所以在这里:

t := &(MyProcessor{2})

t的类型将是*MyProcessor

你的错误行:

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

右侧表达式的类型再次是*MyProcessor。它是一个指向具体类型的指针。p的类型是*LogProcessor,它是指向另一个类型的指针。可赋值性规则在这里不适用,因此该值无法赋给变量p

请注意,有一个可赋值性规则:

> 如果满足以下条件之一,则值x可赋给类型为T变量(“x可赋给T”):
>
> - ...
> - T是一个接口类型,并且x实现T

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

相反,如果你使用“只是”接口类型:

var p LogProcessor = &(MyProcessor{4}) // 这样可以工作!

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

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

英文:

The expression MyProcessor{2} is a composite literal. It is valid to take the address of a composite literal, and it will be of type *MyProcessor.

So here:

t := &(MyProcessor{2})

Type of t will be *MyProcessor.

Your failing line:

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

The type of the expression on the right hand side is again *MyProcessor. It's a pointer to a concrete type. The type of p is *LogProcessor, it's a pointer to another type. Assignability rules don't apply here, so the value is simply not assignable to the variable p.

Note that there is an assignability rule:

> A value x is assignable to a variable of type T ("x is assignable to T") if one of the following conditions applies:
>
> - ...
> - T is an interface type and x implements T.

In your example p's type is not an interface type, but a pointer to interface. You rarely (if ever) need this in go.

Instead if you use "just" the interface type:

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

This works because the concrete type *MyProcessor implements the interface type LogProcessor. You also don't need the parenthesis, you may simply use &MyProcessor{4}.

Then of course you can't dereference p (as it's not a pointer), so you have to use p.Init().

答案2

得分: 1

它失败是因为你正在使用一个指向接口的指针,如果你移除变量p的LogProcessor指针,它就能正常工作。

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} // 移除接口类型的指针后可以正常工作
    fmt.Println((*t).Init(), (p).Init())
}
英文:

it is failing because you are using a pointer to an interface, if you remove the pointer to LogProcessor for var p it works

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())
}

huangapple
  • 本文由 发表于 2021年8月10日 18:34:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/68725213.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定