2016-07-26 11 views
2

私は彼らの基盤とその上に構築されたバリアントとしてベース構造体を持つ構造体のセットを構築しようとしてきました。しかし、共通コードが基本構造体にあるときに構造体がそれ自身を識別する方法はないように見えます。私はこれをどのようにしなければならないのですか?ゴランのアイデンティティ比較?

package main 

import (
    "fmt" 
) 

type Base interface { 
    IsMe(other Base) bool 
} 

type Block struct { 
} 

func (b *Block) IsMe(other Base) bool { 
    return b == other 
} 

type Block2 struct { 
    Block 
} 

func main() { 
    b1 := &Block{} 
    b2 := &Block2{} 
    fmt.Printf("b1.IsMe(b1): %v\n", b1.IsMe(b1)) 
    fmt.Printf("b1.IsMe(b2): %v\n", b1.IsMe(b2)) 
    fmt.Printf("b2.IsMe(b1): %v\n", b2.IsMe(b1)) // Wrong result! 
    fmt.Printf("b2.IsMe(b2): %v\n", b2.IsMe(b2)) // Wrong result! 
} 
+0

だけ明確にするために、私はこれを追加することができます知っている: FUNC(B *ブロック2)ISME(その他ベース)BOOL { リターンB ==他の } と私は、正しい結果を取得します。しかし、私はすべてのサブ構造体に同じボイラープレートコードを書いてはいけません。 –

+0

http://stackoverflow.com/questions/35546054/golang-equivalent-of-is-operator-in-python – IanAuld

+1

おかげで@IanAuldが、そのリンクは、この特定の問題に関連していないようです。関与するインタフェースがあることに注意してください。サイドノートで –

答えて

1
package main 

import (
    "fmt" 
    "reflect" 
) 

type Base interface { 
    IsMe(other Base) bool 
} 

type Block struct { 
    _ [1]byte // size of struct must be greater than zero 
} 

func (b *Block) IsMe(other Base) bool { 
    x := reflect.ValueOf(b) 
    y := reflect.ValueOf(other) 
    return x.Pointer() == y.Pointer() 
} 

type Block2 struct { 
    Block // "parent" needs to be first element 
} 

func main() { 
    b1 := &Block{} 
    b2 := &Block2{} 
    fmt.Printf("b1.IsMe(b1): %v\n", b1.IsMe(b1)) 
    fmt.Printf("b1.IsMe(b2): %v\n", b1.IsMe(b2)) 
    fmt.Printf("b2.IsMe(b1): %v\n", b2.IsMe(b1)) 
    fmt.Printf("b2.IsMe(b2): %v\n", b2.IsMe(b2)) 
} 

https://play.golang.org/p/Dx0Ze3euFY

+0

ありがとうございます。これはトリックでした。Pointer()== reflect.ValueOf(other).Pointer() –

+0

@RichardWilkes:IsMe()の内容をこれに変更して、安全でないパッケージの使用を排除しました:return reflect.ValueOf(Base(b)はい。更新された回答をご覧ください。 –

2

あなたが本当にそれに偽の継承の仕方をしたい場合、あなたはそれをあなたがそれをやった方法を行う確かにすることができますが、言語があるので、それは本当に唯一unsafeまたはreflectで動作しますあなたがしたいことを目的としたものではありません。

あなたの問題はx.IsMeは埋め込みを使用するときにどこから来るかで始まります。あなたがこの方法IsMe

type Block struct {} 
func (b *Block) IsMe(other Base) bool { return b == other } 
type Block2 struct { Block } 

を書くとき、実際にBlock代わりのBlock2に関連して、結合されます。だから、Block2のインスタンスにIsMeを呼び出すと、実際には詳細に、Blockでそれを呼んでいる:

b2 := Block2{} 
fmt.Println(b2.IsMe)  // 0x21560 
fmt.Println(b2.Block.IsMe) // 0x21560 

どちらの方法が同じアドレスを持っています。これは、b2がメソッドIsMeを持っていても、BlockからBlock2およびを継承していないの外側にのみ伝播されることを示しています。これは、順番に、あなたが常に効果的にこのコードを実行していることを意味します

あなたは2つの完全に異なるインスタンスを比較しているので、明らかに動作することはできません
b1 := Block{} 
b2 := Block2{} 
b2_embedded_block := b2.Block 
b2_embedded_block.IsMe(b2) 
b2_embedded_block.IsMe(b1) 
// ... 

。あなたが本当に何をすべき

は平等を決定するためにあなたの埋め込みチェーンの外にいくつかの機能を使用することです。例(On Play):

func IsEq(a,b Base) bool { 
    return a == b 
} 

これは実際に正しいインスタンスを比較します。

+0

これは私がやりたかったのですが、オブジェクトそのものが他の場所に保存されているインターフェイスと比較する必要があるため、コードをすべてのバリエーションに複製することなく機能させるきれいな方法を見つけることができませんでした。 –

+0

あなたの例はおそらく根本的な問題を強調するために抽象化していますが、あなたがきれいな解決策を見つけることができなかったという事実は、あなたの最初のアプローチに欠陥があることを示しているかもしれません。あなたが今それをやっている方法( 'reflect'を使う)は解決策ではなく、回避策です。 – nemo