2 回答

TA贡献1895条经验 获得超3个赞
不要使用指向接口类型的指针,只使用接口类型。
Queuable是一种接口类型,因此在您使用 的代码中的任何地方*Queuable,都将其更改为Queuable. 例如:
type Queuable interface {
Next() Queuable
}
type Node struct {
value interface{}
next Queuable
}
// Next gets the next object
func (n *Node) Next() Queuable {
return n.next
}
...
在 Go 中,接口类型的值存储一对:分配给变量的具体值,以及该值的类型描述符。
更多关于接口的内部结构:反射定律#接口的表示
所以你几乎不需要一个指向接口的指针。一个接口包含一个键值对,其中键可以是一个指针。接口指针有意义的罕见情况是,如果您想修改传递给另一个函数的接口类型变量的值。
在您的示例中,该类型*Job实现了Queuable因为它有一个带有接收器类型的方法*Job,因此在需要值的任何地方Queuable,*Job都可以使用值(并且Queuable将创建和使用类型的隐式接口值)。
回到你的例子:
您Queuable只定义了一种方法来获取队列中的下一个元素,但没有定义一种方法来将它排入队列,这将使该解决方案失去灵活性。单个Next()方法仅描述它是“排队的”,但它不是(必然)“可排队的”。
为了排队,我还要添加另一种方法:SetNext(Queuable)
type Queuable interface {
Next() Queuable
SetNext(Queuable)
}
它的实现Node可以是例如:
func (n *Node) SetNext(q Queuable) { n.next = q }
在Go Playground上试试。
另请注意,Nodeand中有一些代码重复Job,即next字段Next()和SetNext()方法。我们可以创建一个基本节点实现,例如:
type Base struct {
next Queuable
}
func (b *Base) Next() Queuable { return b.next }
func (b *Base) SetNext(q Queuable) { b.next = q }
现在您可以将这种Base类型嵌入到将“继承”字段和方法的具体Node和Job实现中,因此您不必在和类型上定义任何这些。nextNext()SetNext()NodeJob
这是Nodeand的完整实现,Job不需要其他任何东西:
type Node struct {
*Base
value interface{}
}
type Job struct {
*Base
instruction string
}
在Go Playground上试试这个。

TA贡献1817条经验 获得超6个赞
永远不要使用指向接口类型的指针,这已经是一个指针了!
因此,要使代码正常工作,请更改*Queuableas Queuable。
type Node struct {
value interface{}
next Queuable
}
// Next gets the next object
func (n *Node) Next() Queuable {
return n.next
}
// Job - A job for the queue
type Job struct {
instruction string
next Queuable
}
但是,您可以使用方法接收器作为指针,具体取决于结构的复杂性。虽然如果使用的 struct 类型很简单,您可以定义使用 struct 值的方法,这种方式在内存中分配一个新地址。如果您使用方法接收器作为指针,它将引用该结构已在内存中占用的地址。
关于接收者的指针与值的规则是值方法可以在指针和值上调用,但指针方法只能在指针上调用。
出现这个规则是因为指针方法可以修改接收者;在一个值上调用它们将导致该方法接收该值的副本,因此任何修改都将被丢弃。因此,该语言不允许这种错误。
经验法则是,为了一致性,最好坚持将方法定义作为指针或方法定义作为整个接口实现中的值。
- 2 回答
- 0 关注
- 173 浏览
添加回答
举报