2017-04-17 69 views
1

添加了getName()函數的典型示例。如何在下面乾燥?

我不知道怎麼能不寫getName()circlerect兩次?

package main 

import "fmt" 
import "math" 

// Here's a basic interface for geometric shapes. 
type geometry interface { 
    area() float64 
    perim() float64 
    getName() string 
} 

// For our example we'll implement this interface on 
// `rect` and `circle` types. 
type rect struct { 
    width, height float64 
    name string 
} 
type circle struct { 
    radius float64 
    name string 
} 

// To implement an interface in Go, we just need to 
// implement all the methods in the interface. Here we 
// implement `geometry` on `rect`s. 
func (r rect) area() float64 { 
    return r.width * r.height 
} 
func (r rect) perim() float64 { 
    return 2*r.width + 2*r.height 
} 
func (r rect) getName() string { 
    return r.name 
} 

// The implementation for `circle`s. 
func (c circle) area() float64 { 
    return math.Pi * c.radius * c.radius 
} 
func (c circle) perim() float64 { 
    return 2 * math.Pi * c.radius 
} 
func (c circle) getName() string { 
    return c.name 
} 

// If a variable has an interface type, then we can call 
// methods that are in the named interface. Here's a 
// generic `measure` function taking advantage of this 
// to work on any `geometry`. 
func measure(g geometry) { 
    fmt.Println(g) 
    fmt.Println(g.area()) 
    fmt.Println(g.perim()) 
    fmt.Println(g.getName()) 
} 

func main() { 
    r := rect{width: 3, height: 4, name: "rect5"} 
    c := circle{radius: 5, name: "circle2"} 

    // The `circle` and `rect` struct types both 
    // implement the `geometry` interface so we can use 
    // instances of 
    // these structs as arguments to `measure`. 
    measure(r) 
    measure(c) 
} 
+3

不,你不能,因爲類型'geometry'是一個接口,因此沒有暴露字段,只暴露方法。 – Adrian

+0

您需要爲每種類型定義方法以滿足接口。你不能讓這個方法比'return c.name'更簡單,所以沒有任何功能去重複數據。 – JimB

+0

@Adrian哎呀,我的錯! –

回答

1

您可以 - 也可能應該 - 將您的幾何類型嵌入另一個包含該名稱的結構類型。除非名稱是「圓形」或「方形」或您有什麼名稱,否則名稱實際上與幾何圖形本身沒有任何關係。所以你可以有:

type namedGeometry struct { 
    geometry 
    name string 
} 

func (ng *namedGeometry) getName() string { 
    return ng.name 
} 

這將服務於相同的目的,保持乾爽,並保持關注點分離。通過嵌入geometry,您仍然可以在namedGeometry實例上調用geometry方法。

0

我會採用類似Adrian's的方法,但是我會在其他類型中嵌入一個基本類型,它具有通用功能。

type baseShape struct { 
    name string 
} 

func (s *baseShape) getName() string { 
    return s.name 
} 

type rect struct { 
    width, height float64 
    baseShape 
} 

type circle struct { 
    radius float64 
    baseShape 
} 

做完這些之後,您只需要實現不同形狀之間每種類型的功能。

+0

通常我們嵌入類型本身,而不是指向類型的指針。這只是增加了一個不必要的間接級別,因此'baseShape'應該嵌入到'rect'和'circle'(而不是'* baseShape')中。 –

+1

@KavehShahbazian你是對的。當返回一個滿足一個接口的類型時,如果這個類型有所有方法的指針接收器,那麼你必須返回一個指向類型的指針([我的意思是一個例子])(https://play.golang.org/p/GngXC1Rze2))。我認爲這裏適用,但顯然不適用。 – Gavin