2016-04-08 12 views
4

私はインターフェイスをよりよく理解しようとしていて、なぜsにフィールドがないのかを理解していません。Width。マイexample is hereインターフェイスでこのフィールドにアクセスできないのはなぜですか?

package main 

import "fmt" 

type shapes interface { 
    setWidth(float64) 
} 

type rect struct { 
    Width float64 
} 

func (r *rect) setWidth(w float64) { 
    r.Width = w 
} 

var allShapes = map[string]shapes{ 
    "rect": &rect{}, 
} 

func main() { 
    r := &rect{} 
    r.setWidth(5) 
    fmt.Println(r.Width) // this works 
    for _, s := range allShapes { 
     s.setWidth(7) 
     fmt.Println(s.Width) // why not??? 
    } 
} 

はなぜrは幅を持っていますが、sないのですか?私が手に正確なエラーは次のとおりです。

s.Width undefined (type shapes has no field or method Width) 
+1

オフトピック:良いスタイルは、集合/コレクションになるまで、クラス/構造体名に単数形を使用することです。したがって、あなたの場合、 'shapes'ではなく' shape'がより適切でしょう。 –

答えて

3

shapesインターフェースは何*rect道具であるが、それは、具体的なタイプ*rectではありません。それは、どんなインタフェースと同様に、それを満たす任意の型を渡すことを可能にするメソッドのセットです。一時的な訪問者のステッカーを渡してビルの上に上がるようにします。

たとえば、ゴーの建物で人間ができることすべてを行い行動できる猿(またはそれが価値のあるもの、イルカ)があれば、彼はガードを通過してエレベーターに上がることができます。しかし、それは彼を遺伝的に人間にすることはない。

Goは静的型です。つまり、同じ基本型を持つ2つの型であっても、型宣言や意識的に型を変換せずに動的に変換または強制変換することはできません。

var a int 
type myInt int 
var b myInt 

a = 2 
b = 3 
b = a   // Error! cannot use a (type int) as type myInt in assignment. 
b = myInt(a) // This is ok. 

が第二のために私と一緒にこのような状況を想像: - :

type circle struct { 
     Radius float64 
} 

func (c *circle) setWidth(w float64) { 
     c.Radius = w 
} 

*circleはと全くまずまずで戻ってあなたのscenerioに今

type MyInt int 
type YourInt int 

type EveryInt interface { 
     addableByInt(a int) bool 
} 

func (i MyInt) addableByInt(a int) bool { 
    // whatever logic doesn't matter 
    return true 
} 


func (i YourInt) addableByInt(a int) bool { 
    // whatever logic doesn't matter 
    return true 
} 

func main() { 
    // Two guys want to pass as an int 
    b := MyInt(7) 
    c := YourInt(2) 

    // Do everything an `EveryInt` requires 
    // and disguise as one 
    bi := EveryInt(b) 
    ci := EveryInt(c) 

    // Hey, look we're the same! That's the closest 
    // we can get to being an int! 
    bi = ci   // This is ok, we are EveryInt brotherhood 
    fmt.Println(bi) // bi is now 2 

    // Now a real int comes along saying 
    // "Hey, you two look like one of us!" 
    var i int 
    i = bi   // Oops! bi has been made 

    // ci runs away at this point 

} 

*circleshapesを実装するに沿って来ると想像shapesですが、はありません。ではありません。。インターフェイスは、基になる型のプロパティに直接アクセスすることはできませんが、実装されたメソッドセットを介してのみ行うことができます。

var r *rect 

// Verify `s` is in fact a `*rect` under the hood 
if r, ok := s.(*rect); ok { 
     fmt.Println(r.Width) 
} 

これが行くような静的型付け言語はより常に高速である理由の核心である:そのインスタンスが具体的な形になるようにプロパティにアクセスするためには、型アサーションは、インターフェイス上で必要とされますダイナミックに型付けされたものです。ほとんどの場合、タイプ強制を動的に処理するために何らかのリフレクションが使用されます。

+0

なぜr.Widthにアクセスできますか? –

+0

@kristen 'r'はすでに具体的な型(つまり' * rect')であるからです。 Goには静的型があります。つまり、同じ基本型を共有する2つの型であっても、型のアサーションや意識的に正しい型を定義することなく相互に変換または強制変換することはできません。インタフェースは具体的な型ではありません。「これをすべて行うことができれば、このタイプのどこにでも行くことができれば」という簡単な方法のセットですが、「彼女のIDを求める」(別名タイプのアサート)までは彼女がタイプになることはありません。 – PieOhPah

2

はシェイプインターフェイスの実装者ですが、forループではrectとして入力されません。 あなたがそうのような具体的なタイプであることのを強制的に型アサーションを行う場合は、次の

s.(*rect).Width 

あなたが欲しいものを得るでしょう。

コンクリートタイプとそのようなインターフェイスを混在させることに注意する必要があります。

+0

"あなたはコンクリートのタイプとそのようなインターフェースを混在させることに注意する必要がありますか?"それから、より良い方法がありますか? –

+0

あなたの例では、なぜmap [string] shapesのこの特定の要素が '* rect'であると仮定できますか?インターフェイスに、必要なものを公開する別の機能が必要ですか?あなたが他の実装(パイの円のような)をしている場合はどうしたらいいですか? –

関連する問題