当前位置: 首页 > 面试题库 >

使用接口为任意类型创建队列

汪茂
2023-03-14
问题内容

作为学习Go的练习,我正在编写一个基本的Queue数据结构。我昨天开始学习有关接口的知识,我认为尝试将其用于本练习将很酷。我要完成的工作是拥有一个Queue可以接受实现此接口的任何类型的对象:

type Queuable interface {
  Next() *Queuable  // This is probably not right
}

基本上,我想要的是能够将任何具有Next()方法的类型添加到我的Queue。所以我尝试的是:

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
}

// Next gets the next object
func (j *Job) Next() *Queuable {
    return j.next
}

// Queue ...
type Queue struct {
    head *Queuable
    size int
}

我的方法看起来像:

func (q *Queue) Enqueue(node *Queuable) {
    ...
}

// Dequeue - Remove a Queueable form the Queue
func (q *Queue) Dequeue() *Queuable {
  result := q.head
  q.head = q.head.Next()
  q.size--
  return result
}

我收到大量这些错误(基本上是在有作业的任何一行上):

current.Next undefined (type *Queuable is pointer to interface, not interface)

因此,最终我想做的是:

func main() {
  queue := NewQueue()  // Helper function not pictured
  job := &Job{"some instructions", nil}
  node := &Node{5, nil}
  queue.Enqueue(node)  // queue = [node]
  queue.Enqueue(job) // queue = [node, job]
  queue.Dequeue() // node
  queue.Dequeue() // job
}

问题答案:

不要使用指向接口类型的指针,而只需使用接口类型。

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](http://play.golang.org/p/2RCRpV_NBX)

还要注意的是有一些代码重复NodeJob,作为nextNext()SetNext()方法。我们可以创建一个基本节点实现,例如:

type Base struct {
    next Queuable
}

func (b *Base) Next() Queuable     { return b.next }
func (b *Base) SetNext(q Queuable) { b.next = q }

现在你可以嵌入这个Base在您的具体类型NodeJob实现其将“继承”的next领域,Next()SetNext()方法,所以你不必定义对任何这些NodeJob类型。

这是全面落实NodeJob,没有别的要求:

type Node struct {
    *Base
    value interface{}
}

type Job struct {
    *Base
    instruction string
}

在上尝试一下[Go Playground](http://play.golang.org/p/Fv9HbYJyhQ)



 类似资料:
  • 我试图创建像@repository这样的系统。

  • 我正在使用openapi生成器生成java类。 我希望模型类实现openapi生成器尚未生成的外部接口。 有什么东西可以在yaml模型中定义,或者有一个属性可以传递给openapi生成器maven插件,允许这种行为? 所需行为的示例:

  • 7.2. 接口类型 接口类型具体描述了一系列方法的集合,一个实现了这些方法的具体类型是这个接口类型的实例。 io.Writer类型是用的最广泛的接口之一,因为它提供了所有的类型写入bytes的抽象,包括文件类型,内存缓冲区,网络链接,HTTP客户端,压缩工具,哈希等等。io包中定义了很多其它有用的接口类型。Reader可以代表任意可以读取bytes的类型,Closer可以是任意可以关闭的值,例如一

  • 我正在使用一个接口来定义一个新类型。这是正确的做法吗?我做如下: 然后,为了实例化它,我必须这样做: 它实际上创建了一个空对象,这不是我想要的;但是如果没有这个,它会引发一个错误,例如,“无法读取未定义的属性‘问题’”。我定义新类型的方法是错误的吗? ====EDIT====以下是我根据你的评论所做的: 然后我说: 然后我仍然得到这个错误:无法读取未定义的属性“push”。我不想在定义接口的地方启

  • 这个问题直接类似于使用TypeScript进行类类型检查

  • 问题内容: 考虑以下代码: 当我们尝试调用新定义的方法时,这是不可能的。这样做的原因是,它被声明为类型的对象,而不是我们新的匿名子类的实例。 因此,我的问题是,是否有任何“不错”的方式来实现这种行为?除了显而易见的(正确地声明类)。 问题答案: 这是不可能的,因为您试图在超类引用上调用方法子类。而且该方法未在超类本身中定义。匿名类只是那里的一个子类。 但是,一种解决方法是进行反思: 该方法将返回的