2015-07-19 50 views
7

說我有兩個結構:兩種不同類型如何在使用接口的golang中實現相同的方法?

type First struct { 
    str string 
} 
type Second struct { 
    str string 
} 

而且我想他們都實現接口A:

type A interface { 
    PrintStr() //print First.str or Second.str 
} 

這似乎是多餘的,以對第一和第二結構像這樣實現:

func (f First) PrintStr() { 
    fmt.Print(f.str) 
} 

func (s Second) PrintStr() { 
    fmt.Print(s.str) 
} 

有沒有辦法讓所有的實現接口A的結構都有一個實現?像這樣的東西,但它似乎並沒有工作:

func (a A) PrintStr() { 
    fmt.Print(a.str) 
} 

謝謝!

+2

擁有2個相同類型的結構似乎有點多餘。 – TheHippo

+0

是的,但這是一個玩具的例子。第一和第二可以共享一些領域而不是其他領域。重點是我想要一個函數以兩種不同類型完全相同的方式運行,而不需要重複代碼。 – Ekaterina

回答

10

,你不行,你可以創建一個基本類型,然後將它嵌入到2結構,因此只需要爲基本類型的實現:

type WithString struct { 
    str string 
} 

type First struct { 
    WithString 
} 

type Second struct { 
    WithString 
} 

type A interface { 
    PrintStr() //print First.str or Second.str 
} 

func (w WithString) PrintStr() { 
    fmt.Print(w.str) 
} 

用法:

a := First{ 
    WithString: WithString{ 
     str: "foo", 
    }, 
} 

Complete Example on Playground

Embed documentation

+1

這個魔法在哪裏定義了一個不可變成員的結構?從你的答案:'type First struct {WithString}'...有沒有關於這個的任何文檔?定義一個類型結構爲另一種類型? – Joey

+1

@Joey這稱爲嵌入,它是一個衆所周知的技術,請參閱https://golang.org/doc/effective_go.html#embedding – SirDarius

1

也許不是最好的方式來解決你的問題,但你可以使用一個包裝,以避免「執行」功能的兩倍,是這樣的:

type First struct { 
    str StringWrapper 
} 
type Second struct { 
    str StringWrapper 
} 


type StringWrapper struct { 
    str string 
} 
func (f StringWrapper) PrintStr() { 
    fmt.Print(f.str) 
} 

func main() { 
    var a First = First{str:StringWrapper{str: "aaa"}}; 
    a.str.PrintStr(); 
} 
2

如果打印邏輯取決於接口,但不能在結構本身,那麼最好是移動打印到工作在接口免費功能。

在你的情況下,該PrintStr方法用於打印一個字符串,其是每個結構中的一員。
在這種情況下,這意味着每個結構應該實現返回用於打印的必要串的接口,並且PrintStr變爲採取Printable參數的函數。

type First struct { 
    str string 
} 
type Second struct { 
    str string 
} 

type Printable interface { 
    String() string 
} 

func (p First) String() string { 
    return p.str 
} 

func (p Second) String() string { 
    return p.str 
} 

func PrintStr(p Printable) { 
    fmt.Print(p.String()) 
} 

您使用A界面的非慣用因爲接口不應該依賴於它的功能實施

取而代之的是,這個解決方案,你仍然可以保持A接口,但簡化各執行:

func (f First) PrintStr() { 
    PrintStr(f) 
} 

func (s Second) PrintStr() { 
    PrintStr(s) 
} 

它仍然是多餘的,但邏輯在於,從那裏調用的函數,限制了需要在修改打印邏輯的情況下進行復制粘貼。

這種模式是在圍棋標準庫中常見的,因爲許多有用的功能是在他們不能擴展,例如io.Reader接口內置。
這是一個只有一個方法一個簡單的界面,但它是從許多其他包徹底使用。
如果您看ioutil.ReadAll函數,可能會認爲它可能已被作爲io.Reader接口的另一種方法實現,但這樣可以讓讀者更簡單,專注於單一方法,同時允許任何實現者免費使用ReadAll。

相關問題