亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

使用接口為任意類型創建隊列

使用接口為任意類型創建隊列

Go
陪伴而非守候 2021-12-20 09:41:43
作為學習 Go 的練習,我正在編寫一個基本的隊列數據結構。我昨天開始學習接口,我認為在這個練習中嘗試使用它們會很酷。我想要完成的是擁有一個Queue可以接受實現此接口的任何類型:type Queuable interface {  Next() *Queuable  // This is probably not right}基本上我想要的是能夠將任何具有Next()方法的類型添加到我的Queue. 所以我嘗試的是:type Node struct {    value interface{}    next  *Queuable}// Next gets the next objectfunc (n *Node) Next() *Queuable {    return n.next}// Job - A job for the queuetype Job struct {    instruction string    next        *Queuable}// Next gets the next objectfunc (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 Queuefunc (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}
查看完整描述

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上試試這個。


查看完整回答
反對 回復 2021-12-20
?
慕的地6264312

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 值的方法,這種方式在內存中分配一個新地址。如果您使用方法接收器作為指針,它將引用該結構已在內存中占用的地址。


關于接收者的指針與值的規則是值方法可以在指針和值上調用,但指針方法只能在指針上調用。


出現這個規則是因為指針方法可以修改接收者;在一個值上調用它們將導致該方法接收該值的副本,因此任何修改都將被丟棄。因此,該語言不允許這種錯誤。


經驗法則是,為了一致性,最好堅持將方法定義作為指針或方法定義作為整個接口實現中的值。


查看完整回答
反對 回復 2021-12-20
  • 2 回答
  • 0 關注
  • 168 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號