2016-05-05 8 views
1

まず、私はGoが新しくなりました。したがって、用語の間違いや間違いを許してください。私は、用語のコマンドの私の欠如は、部分的には、次の質問への答えを見て何時間もの後に見つからないために責任があると思う。組み込み関数内の関数へのアクセス

要するに

、私は次のコードの出力はになりたい出力がある代わりに

I am the Adult 
I am the Child 

I am the Adult 
I am the Adult 

コード:本質的には

package main 

import "fmt" 

type Human struct { 
    age uint 
    name string 
} 

func (h Human) sayName() error { 
    fmt.Println("I am the Adult") 
    return nil 
} 

func (h Human) Introduce() error { 
    h.sayName() 
    return nil 
} 

type Child struct { 
    Human 
} 

func (c Child) sayName() error { 
    fmt.Println("I am the Child") 
    return nil 
} 

func main() { 
    h := Human{} 
    h.Introduce() 

    c := Child{Human{}} 
    c.Introduce() 
} 

ので、 Introduce()は埋め込み型のHumanでのみ実装されていますが、sayName()を呼び出します。これは埋め込み型の両方に実装されていますタイプと埋め込みタイプです。

組み込みのHuman構造体が埋め込まれていることを「認識」していないため、Child.sayNameを呼び出すことができず、独自のsayName()関数だけを呼び出すことができるため、現在の出力はそのままです。

Human.sayName()を代替のsayName()関数で "置き換える"ことができるHuman構造体(または構造体を埋め込む構造体)をインスタンス化する方法はありますか?

答えて

1

このような遅延バインドの動作を取得する方法は、インターフェイスを使用することです。IntroducesayNameメソッドを必要とするインターフェイス上のメソッドであった場合、HumanChildはどちらもインターフェイスを満たし、Introduceとなる可能性があり、どちらの場合でも適切なsayNameメソッドが呼び出されるのは、インターフェイスタイプ、代わりにHumanを使用します。

+0

私はあなたが何を意味するかを見ていると思います。任意の特定の構造体によって受け取られる関数であるIntroduce()の代わりに、定義された受信者を持たない関数に変更されますが、Talkerが実装する構造体として定義されている "Talker" sayName()? – davidr

+0

@ user306537はい。悲しいことに、インタフェース受信機能を持つメソッドを定義することはできません(これは、インタフェースを役割として機能させることになります)。 – hobbs

0

あなたがしたいことはできません。あなたが述べたように、HumanタイプはChildタイプに埋め込まれていることを決して知らないかもしれません。Introduceが呼び出されるとのChildタイプのバージョンを呼び出す方法がありません。関係を逆転させようとしています。組み込み型を埋め込み型のメソッドの別のバージョンに呼び出すようにしています。

埋め込み型のメソッドは、埋め込み型の範囲に持ち上げられますが、それは分かりやすい一方通行です。このような状況では、コードを構造化するだけで済みます。おそらく、あなたが探している動作は、埋め込みではなくインターフェイスを使用して実現できます。私はもっ​​と多くの例を提供しますが、あなたのコードサンプルではあまり言わないことがあります。明らかにここで問題を解決するには、sayName()と呼んで、何もしないので、最初にIntroduceを定義しません。

逆方向に埋め込むことができます。 Humanの両方がsayName()の定義を持っている。このような場合に、Childへの参照が含まれていないが、Humanへの参照を持ってChildないと、Childc.Human.sayName()を行うことによってHuman年代を呼び出すことができます。だから私の直感はあなたが間違った方向に埋め込まれたとか、インターフェースを使うべきだと言っています。これは純粋に前提ですが、私はあなたが間違った考えをしていると思います。なぜならHumanを「大人」(親のようなもの)とChild(子クラスのようなもの)と呼んでいるからです。これはまったく当てはまりません。埋め込みは組み込み型と同じですが、埋め込み型のメソッドとフィールドだけが持ち上げられたり持ち上げたり、埋め込みの範囲に移動したと言いたい言葉があれば、それは言われている、私はそれのまわりで多くの混乱を参照してくださいと、それは本当にそれが構成時に相続人のようにこれを見ているので、ほとんど常にです。

+0

感謝。私はそれほど恐れた。この動作を意図した実際のアプリケーションは、ハードウェア管理のためのCライブラリのGoバインディングをテストするためのものでした。私は関数内でcgoを呼び出し、その関数がテストされているときは、元の "device"型を埋め込んだ "testdevice"を作成したいと思いました。ここでは、cgo関数呼び出し関数を "testdevice"テーブルからC構造体を戻したばかりです。私はドローイングボードに戻る必要があると思う。 – davidr

+0

@ user306537 hobbsも以下のように指摘していますが、これを行う方法はインターフェイスを使用する方法です。埋め込みを使用するのではなく、それらの関数がインターフェイスから呼び出されるようにします。次に、テストコードでは、実際のインターフェイスの代わりに使用するインターフェイスの独自の実装があります。これは私の経験では、このようなことを達成するための最も一般的な方法です。あなたはまた、httpdtriptripperのようなもので、stdライブラリのかなりの部分に同様のデザインを参照してください。 – evanmcdonnal

0

私は間違って考えていました。 hobbsとevanmcdonnalが言ったように、これを行う「正しい」方法は、インタフェース引数を持つ関数をIntroduce()関数にし、次にChildとHumanの両方が実装するインタフェースを作成することです。

以下は、所望の出力が得られます。

package main 

import "fmt" 

type Talker interface { 
    sayName() error 
} 

type Human struct { 
    age uint 
    name string 
} 

func (h Human) sayName() error { 
    fmt.Println("I am the Adult") 
    return nil 
} 

type Child struct { 
    Human 
} 

func Introduce(t Talker) error { 
    t.sayName() 
    return nil 
} 

func (c Child) sayName() error { 
    fmt.Println("I am the Child") 
    return nil 
} 

func main() { 
    h := Human{} 
    Introduce(h) 

    c := Child{Human{}} 
    Introduce(c) 
} 
答えのために非常に多くの
関連する問題