当使用接口时,如何操作结构字段

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

Manipulate struct field when using interface

问题

标题可能有些误导,但要点是...

我有一个单一的接口Expression

type Expression interface {
    String() // 在下面的实现中被省略
}

该接口由多个结构体实现,其中一些结构体将同一个接口作为字段值实现:

type IdentExpression struct {
    value string
}

type UnaryExpression struct {
    token string
    value Expression
}

func (a *UnaryExpression) Simplify() {
    var finalValue Expression
    switch a.value.(type) {
    case UnaryExpression:
        tmp := a.value.(UnaryExpression)
        switch tmp.value.(type) {
        case UnaryExpression:
            tmp = tmp.value.(UnaryExpression)
            finalValue = tmp.value
        }
    }

    a.value = finalValue
}

给定表达式-(-(-(1)))UnaryExpression.Simplify()将简化表达式为-(1)。 (play)

我想用Simplify()方法扩展该接口:

type Expression interface {
    Simplify()
    String() string
}

// ...

func (a IdentExpression) Simplify() {} // 什么也不做

结果代码无法工作 (play):

> main.go:29: impossible type switch case: a.value (type Expression) cannot have dynamic type UnaryExpression (missing Simplify method)
>
> main.go:30: impossible type assertion:
>
> UnaryExpression does not implement Expression (Simplify method has pointer receiver)
> main.go:59: cannot use UnaryExpression literal (type UnaryExpression) as type Expression in field value:
>
> UnaryExpression does not implement Expression (Simplify method has pointer receiver)
>
> main.go:60: cannot use UnaryExpression literal (type UnaryExpression) as type Expression in field value:
>
> UnaryExpression does not implement Expression (Simplify method has pointer receiver)

我找到了这个答案,看起来很相似,但我不知道如何在我的情况下应用它。

英文:

The title might be misleading, but to the point...

I have a single interface Expression:

type Expression interface {
	String() // skiped in implementation below
}

The interface is implemented by multiple structs, some of which implements same interface as a field value:

type IdentExpression struct {
	value string
}

type UnaryExpression struct {
	token string
	value Expression
}

func (a *UnaryExpression) Simplify() {
	var finalValue Expression
	switch a.value.(type) {
	case UnaryExpression:
		tmp := a.value.(UnaryExpression)
		switch tmp.value.(type) {
		case UnaryExpression:
			tmp = tmp.value.(UnaryExpression)
			finalValue = tmp.value
		}
	}

	a.value = finalValue
}

Given expression -(-(-(1))), UnaryExpression.Simplify() will simplify the expression to -(1). (play)

I would like to extend the interface with Simplify() method:

type Expression interface {
	Simplify()
	String() string
}

// ...

func (a IdentExpression) Simplify() {} // do nothing

Resulting code does not work (play):

> main.go:29: impossible type switch case: a.value (type Expression) cannot have dynamic type UnaryExpression (missing Simplify method)
>
> main.go:30: impossible type assertion:
>
> UnaryExpression does not implement Expression (Simplify method has pointer receiver)
> main.go:59: cannot use UnaryExpression literal (type UnaryExpression) as type Expression in field value:
>
> UnaryExpression does not implement Expression (Simplify method has pointer receiver)
>
> main.go:60: cannot use UnaryExpression literal (type UnaryExpression) as type Expression in field value:
>
> UnaryExpression does not implement Expression (Simplify method has pointer receiver)

I have found this answer, which looks similar however I do not know how to apply it in my case.

答案1

得分: 4

这里的关键是,在你对UnaryExpressionSimplify()方法的定义中,你使用了指针接收器:

func (a *UnaryExpression) Simplify()

而你实现的其他方法没有使用指针接收器:

// 一个例子
func (a IdentExpression) Simplify() {}

通常,在Go语言中,最佳实践是让同一类型的所有方法都使用相同类型的接收器(即,如果一个方法使用了指针接收器,那么所有方法都应该使用指针接收器;同样地,如果一个方法使用了非指针接收器,那么所有方法都应该使用非指针接收器)。

在这种情况下,如果你从UnaryExpressionSimplify方法中移除指针接收器,代码将能够编译通过。希望对你有帮助!

编辑:这里有一个更详细的答案,解释了为什么会出现这个错误,非常值得一读。

英文:

The key here is that you are using a pointer receiver in your definition of Simplify() with respect to UnaryExpression:

func (a *UnaryExpression) Simplify()

The other methods you are implementing don't use a pointer receiver:

// One example
func (a IdentExpression) Simplify() {}

Typically, in Go, it is considered best practice to have all methods on the same type use the same type of receiver (i.e. if one method uses a pointer receiver, they all should. Likewise, if one method uses a non-pointer receiver, they all should for that particular type).

In this case, the code will compile if you remove the pointer receiver from the Simplify method of UnaryExpression. Hope this helps!

Edit: Here is a more comprehensive answer that explains exactly why this error happens, it's really a good read.

huangapple
  • 本文由 发表于 2017年7月23日 01:15:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/45257237.html
匿名

发表评论

匿名网友

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

确定