使用接口为任意类型创建队列 [英] Using Interfaces to Create a Queue for Arbitrary Types

查看:171
本文介绍了使用接口为任意类型创建队列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

作为学习的一种练习,我正在编写一个基本的队列数据结构。我在昨天开始学习接口,我认为尝试将它们用于此练习会很酷。我试图完成的是有一个 Queue ,它可以接受任何实现此接口的类型:

 类型Queueable接口{
Next()* Queuable //这可能不正确
}

基本上我想要的是可以将任何具有 Next()方法的类型添加到我的队列。所以我试过的是:

 类型Node结构{
value interface {}
next * Queuable
}

//下一个获取下一个对象
func(n * Node)Next()* Queuable {
return n.next
}

//作业 - 作业队列
类型作业结构{
指令字符串
下一个*可排队
}

/ / Next获取下一个对象
func(j * Job)Next()* Queuable {
return j.next
}

// Queue ...
类型Queue struct {
头*可排队
大小int
}

我的方法看起来像:

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

// Dequeue - 从队列中删除Queueable
func(q * Queue)Dequeue()* Queuable {
result:= q.head
q.head = q.head.Next()
q.size--
返回结果
}

我遇到了很多这样的错误(basicall y:

  current.Next未定义(类型* Queuable是指向接口的指针,而不是接口)

因此,最终我想要做的是:

  func main(){
queue:= NewQueue()//助手函数未显示
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 。例如:

$ $ p $ 类型Queueable接口{
下一个()Queueable
}

类型Node结构{
value interface {}
下一个可排序的
}

//下一个获取下一个对象
func(n * Node) Next()Queuable {
return n.next
}

...



在Go中,接口类型的值存储一对:分配给该变量的具体值,以及该值的类型描述符。



更多信息界面的内部:

所以你几乎不需要指向接口的指针。一个接口包含一个键值对,其中键可以是一个指针。如果你想修改传递给另一个函数的接口类型变量的值,那么这种情况很少见。



在你的例子中,类型 * Job 实现 Queuable ,因为它有一个接收方类型为 * Job Queuable 值的地方,都可以使用 * Job 值将创建并使用 Queuable 类型的隐式接口值)。 : $ b

您的 Queuable 只定义了一个获取队列中下一个元素的方法,但不能一个排队它会使这个解决方案失去灵活性。一个 Next()方法只描述它是<排队> ,但它不是(必然)queuable



成为 queuable 我也会添加另一个方法: SetNext(Queuable)

 类型Queueable接口{
Next()Queuable
SetNext(Queuable)
}

例如 Node
$ b

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

试试 Go Playground



另请注意, Node 作业,即下一个字段和下一个() 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 实现将继承下一个字段并且 Next() SetNext()方法,所以您不必在 Node Job 类型。

这是完整的实现节点作业,其他都不需要:

类型Node结构{
* Base
接口{}
}

类型作业结构{
* Base
指令字符串
}

请在 Go Playground


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
}

解决方案

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 Go Playground.

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 Go Playground.

这篇关于使用接口为任意类型创建队列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆