dougu2036 2016-02-24 07:27
浏览 42
已采纳

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

As an exercise for learning Go I am writing a basic Queue data structure. I started learning about interfaces yesterday I thought it would be cool to try and use them for this exercise. What I am trying to accomplish is to have a Queue that can accept any type that implements this interface:

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

Basically what I want is to be able to add any type that has a Next() method to my Queue. So what I tried was:

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
}

And my methods looking like:

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
}

I'm getting a ton of these errors (basically on any line with an assignment):

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

So ultimately what I would like to do would be:

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
}
  • 写回答

2条回答 默认 最新

  • doutuo6048 2016-02-24 07:38
    关注

    Don't use pointer to an interface type, just the interface type.

    Queuable is an interface type, so everywhere in your code where you used *Queuable, change it to Queuable. For example:

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

    In Go a value of interface type stores a pair: the concrete value assigned to the variable, and that value's type descriptor.

    More about interface's internals: The Laws of Reflection #The representation of an interface

    So you almost never need a pointer to interface. An interface contains a key-value pair where the key may be a pointer. The rare case when a pointer to interface makes sense is if you want to modify the value of a variable of interface type passed to another function.

    In your example the type *Job implements Queuable because it has a method with receiver type *Job, and so everywhere where a value of Queuable is required, a value of *Job can be used (and an implicit interface value of type Queuable will be created and used).

    Getting back to your example:

    Your Queuable only defines a method to get the next element in the queue, but not one to enqueue it which will make this solution lose flexibility. A single Next() method only describes that it is "queued" but it is not (necessarily) "queuable".

    To be queuable I would also add another method: SetNext(Queuable)

    type Queuable interface {
        Next() Queuable
        SetNext(Queuable)
    }
    

    Its implementation on Node can be for example:

    func (n *Node) SetNext(q Queuable) { n.next = q }
    

    Try it on the <kbd>Go Playground</kbd>.

    Also note that there is some code duplication in Node and Job, being the next field and Next() and SetNext() methods. We could create a base node implementation, e.g.:

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

    And now you can embed this Base type in your concrete Node and Job implementations which will "inherit" the next field and Next() and SetNext() methods, so you don't have to define any of these on the Node and Job types.

    This is the full implementation of Node and Job, nothing else is required:

    type Node struct {
        *Base
        value interface{}
    }
    
    type Job struct {
        *Base
        instruction string
    }
    

    Try this on the <kbd>Go Playground</kbd>.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 使用EMD去噪处理RML2016数据集时候的原理
  • ¥15 神经网络预测均方误差很小 但是图像上看着差别太大
  • ¥15 Oracle中如何从clob类型截取特定字符串后面的字符
  • ¥15 想通过pywinauto自动电机应用程序按钮,但是找不到应用程序按钮信息
  • ¥15 如何在炒股软件中,爬到我想看的日k线
  • ¥15 seatunnel 怎么配置Elasticsearch
  • ¥15 PSCAD安装问题 ERROR: Visual Studio 2013, 2015, 2017 or 2019 is not found in the system.
  • ¥15 (标签-MATLAB|关键词-多址)
  • ¥15 关于#MATLAB#的问题,如何解决?(相关搜索:信噪比,系统容量)
  • ¥500 52810做蓝牙接受端