2013-11-23 22 views
5

aşağıdaki türleri vardır: Ben neden bir işlevin oldukça iyi bir kavrayışa sahip düşünüyorumÇağrı Git fonksiyonu (B uygulayan A)

type Statement interface { 
    Say() string 
} 

type Quote struct { 
    quote string 
} 

func (p Quote) Say() string { 
    return p.quote 
} 

func Replay(conversation []Statement) { 
    for _, statement := range conversation { 
     fmt.Println(statement.Say()) 
    } 
} 

o []Statement tipinde bir parametre kabul eder, []Quote ile çağrılmaz; Quote, Statement uygulandığında bile, []Quote, []Statement uygulanmaz. []Statement, bir arayüz bile değil. Bu, slice of Statement türüne sahiptir. Go, bir türden bir arabirim türüne dolaylı olarak dönüştürürken, A türünde bir dilimden, B arabiriminin bir dilimine örtük bir dönüşüm gerçekleştirmez.

Biz açıkça açıklamalara tırnak dönüştürebilirsiniz:

conversation := []Quote{ 
    Quote{"Nice Guy Eddie: C'mon, throw in a buck!"}, 
    Quote{"Mr. Pink: Uh-uh, I don't tip."}, 
    Quote{"Nice Guy Eddie: You don't tip?"}, 
    Quote{"Mr. Pink: Nah, I don't believe in it."}, 
    Quote{"Nice Guy Eddie: You don't believe in tipping?"}, 
} 

// This doesn't work 
// Replay(conversation) 

// Create statements from quotes 
statements := make([]Statement, len(conversation)) 
for i, quote := range conversation { 
    statements[i] = quote 
} 

Replay(statements) 

Şimdi bu Tekrar o Replay kullanımı var ne kadar kolay kendi yolumdan gitmek istiyor kitaplığın bir parçası olduğunu söylüyorlar. Bu nesneler, Deyim arabirimini uyguladığı sürece, herhangi bir nesne dilimiyle Yeniden Oynat'ı çağırmanıza izin verir. Bunu yapmak için sahip olduğu Aşağıdaki dönüşüm yöntemi:

func Replay(its interface{}) { 
    conversation := ConvertToStatements(its) 
    for _, statement := range conversation { 
     fmt.Println(statement.Say()) 
    } 
} 

Biz artık doğrudan tırnak Replay çağırabilirsiniz:

func ConvertToStatements(its interface{}) ([]Statement, error) { 
    itsValue := reflect.ValueOf(its) 
    itsKind := itsValue.Kind() 
    if itsKind != reflect.Array && itsKind != reflect.Slice { 
     return nil, fmt.Errorf("Expected items to be an Array or a Slice, got %s", itsKind) 
    } 
    itsLength := itsValue.Len() 
    items := make([]Statement, itsLength) 
    for i := 0; i < itsLength; i++ { 
     itsItem := itsValue.Index(i) 
     if item, ok := itsItem.Interface().(Statement); ok { 
      items[i] = item 
     } else { 
      return nil, fmt.Errorf("item #%d does not implement the Statement interface: %s", i, itsItem) 
     } 
    } 
    return items, nil 
} 

Tekrar şöyle

Replay(conversation) 

Son olarak, sorum: A, Deyim arayüzünü uyguladığı sürece, Replay'in herhangi bir A türünde bir dilimi kabul etmesine izin vermenin daha basit bir yolu var mı?

cevap

2

sizin (uzun) soruya çok kısa cevap: Hayır

Ben ConvertToStatment ve Tekrar boş bir arayüz alma çözüm bir "güzel" çözüm olduğunu sanmıyorum: Ben func Replay([]Statement) tercih ediyorum ve arayanlar bir Dilimler bölümü sağlamalıdır. Bu, daha açık ve arayanlar, ürünlerini [] Bildirimi'ne dönüştürebilir veya doğrudan [] Bildirimi oluşturabilir.

5

[]Quote diliminin bellek içi yerleşimi, []Statement diliminden farklıdır, bu nedenle bu mümkün değildir.

[]Quote diliminin yedekleme dizisi, sıralı Quote yapılarından oluşurken, []Statement diliminin yedekleme dizisi, arabirim değişkenlerinden oluşur. Arabirim değişkeni, Quote yapısını (veya başka herhangi bir türde arabirimi uygular) tutmanın yanı sıra, içerilen değer için bilgi yazmak için bir işaretçiyi de saklar. Bu, Say yöntem çağrısının nasıl gönderileceğini belirlemek için gereklidir.

Farklı veri düzeni, iki dilim türünü güvensiz atmalarda bile kullanamayacağınız anlamına gelir: bir türünüz varsa ve diğerine ihtiyacınız varsa, bunlar arasında el ile dönüştürmeniz gerekir.

0

Aşağıdaki kod, her ikisi de Say() işlevini uygulayan iki farklı yapı türüne sahiptir.Her iki türlerini içeren bir dizi oluşturmak ve Replay() arayıp o ne istersen yap sahip olabilir:

package main 

import "fmt" 

type Statement interface { 
    Say() string 
} 
type Statements []Statement 

type Quote struct { 
    quote string 
} 
type Quotes []Quote 

func (p Quote) Say() string { 
    return p.quote 
} 

type Attributed struct { 
    who string 
    quote string 
} 

func (p Attributed) Say() string { 
    return p.who + ": " + p.quote 
} 


func Replay(conversation []Statement) { 
    for _, s := range conversation { 
     fmt.Println(s.Say()) 
    } 
} 

func (q Quotes) toStatements() Statements { 
    conv := make(Statements, len(q)) 
    for i, v := range q { 
     conv[i] = Statement(v) 
    } 
    return conv 
} 

func main() { 
    conversation := Statements{ 
     Quote{"Nice Guy Eddie: C'mon, throw in a buck!"}, 
     Quote{"Mr. Pink: Uh-uh, I don't tip."}, 
     Attributed{"Nice Guy Eddie", "You don't tip?"}, // <= another type 
     Quote{"Mr. Pink: Nah, I don't believe in it."}, 
     Quote{"Nice Guy Eddie: You don't believe in tipping?"}, 
    } 

    myquotes := Quotes{ 
     Quote{"Nice Guy Eddie: C'mon, throw in a buck!"}, 
     Quote{"Mr. Pink: Uh-uh, I don't tip."}, 
     Quote{"Nice Guy Eddie: You don't tip?"}, 
     Quote{"Mr. Pink: Nah, I don't believe in it."}, 
     Quote{"Nice Guy Eddie: You don't believe in tipping?"}, 
    } 

    Replay(conversation) 
    Replay(myquotes.toStatements()) 
} 

Replay()

değiştirmek veya Attributed{} hakkında hiçbir şey bilmiyor. Quotes & Statements dilimleri için türleri tanıtmanız gerekir.

İlgili konular