ロブ・パイクが「ゴーは作曲について」と言うとき、彼は正確に何を意味しますか?[閉まっている]


12

より少ないから指数関数的に

C ++とJavaが型の階層と型の分類に関するものである場合、Goは合成に関するものです。

回答:


13

彼は、次の順序で何かを使用することを意味します。

class A : public B {};

JavaやC ++のようなもので、Goで使用するもの(同等のもの):

class A {
    B b;
};

はい、これは継承のような機能を提供します。上記の例を少し拡張してみましょう。

struct B {
    int foo() {}
};

struct A { 
    B b;
};

A a;

a.foo();  // not allowed in C++ or Java, but allowed in Go.

ただし、これを行うには、C ++またはJavaで許可されていない構文を使用します。埋め込みオブジェクトを独自の名前なしで残すため、次のようになります。

struct A {
   B;
};

1
私は好奇心が強いです、私はC ++でそれをします(構成を好む)。Java / C ++で継承する必要がある場合、作成に役立つ機能を提供しますか?
ダグT.

2
@DougT .:はい、私はそれが許可するもの(の一部)の一般的なアイデアを示す例で編集しました。
ジェリーコフィン

2
これはポイントを逃していると思います。違いは、埋め込みを使用して分類法を構築することを意味する単なる構文上の違いではありません。実際のところ、OOPメソッドのオーバーライドがないため、古典的な分類法を構築できず、代わりに構成を使用する必要があります。
デニス・Séguret

1
@dystroy:Javaと比較して、おそらくポイントがあります。C ++と比較すると、それほど多くはありません。(少なくとも手がかりのある人の間では)それらの巨大な分類法は20年近く前に最後に見られたからです。
ジェリーコフィン

1
@dystroy:あなたはまだ理解していません。現代のC ++の3レベルの階層は、前代未聞です。C ++では、iostreamライブラリと例外階層にこれらが表示されますが、他のどこにもほとんどありません。iostreamsライブラリが今日設計されていた場合、それもそうではないと言うのは安全だと思います。結論:C ++についての議論は、C ++との接触の程度よりも少ないことを示しています。何十年も使用していないことを考えると、それは理にかなっています。意味をなさないのは、その古い経験に基づいてC ++がどのように使用されるかを言おうとすることです。
ジェリーコフィン

8

この質問/問題は、これに似てます。

Goでは、OOPは実際にはありません。

オブジェクトを「特化」したい場合は、埋め込みによって構成しますが、これは構成ですが、いくつかの利点を備えており、部分的に継承似ています。このようにします:

type ConnexionMysql struct {
    *sql.DB
}

このサンプルでは、​​ConnexionMysqlは* sql.DBの特殊化であり、ConnexionMysqlで* sql.DBで定義されている関数を呼び出すことができます。

type BaseMysql struct {
    user     string
    password string
    database string
}

func (store *BaseMysql) DB() (ConnexionMysql, error) {
    db, err := sql.Open("mymysql", store.database+"/"+store.user+"/"+store.password)
    return ConnexionMysql{db}, err
}

func (con ConnexionMysql) EtatBraldun(idBraldun uint) (*EtatBraldun, error) {
    row := con.QueryRow("select pv, pvmax, pa, tour, dla, faim from compte where id=?", idBraldun)
    // stuff
    return nil, err
}

// somewhere else:
con, err := ms.bd.DB()
defer con.Close()
// ...
somethings, err = con.EtatBraldun(id)

したがって、一見すると、この構成は通常の分類法を作成するためのツールであると考えるかもしれません。

だが

* sql.DBで定義された関数が* sql.DBで定義された他の関数を呼び出す場合、ConnexionMysqlで再定義された関数が存在しても呼び出しません。

古典的な継承では、次のようなことがよく行われます。

func (db *sql.DB) doComplexThing() {
   db.doSimpleThing()
   db.doAnotherSimpleThing()
}

func (db *sql.DB) doSimpleThing() {
   // standard implementation, that we expect to override
}

つまりdoComplexThing、特殊化の呼び出しに関する組織としてスーパークラスで定義します。

しかし、Goでは、これは特殊な関数ではなく「スーパークラス」関数を呼び出します。

そのため、* sql.DBで定義されているがConnexionMySQL(または他の専門分野)で再定義されている関数を呼び出す必要があるアルゴリズムが必要な場合、このアルゴリズムを* sql.DBの関数として定義することはできませんが、他の場所で定義する必要がありますそして、この関数は提供された特殊化への呼び出しのみを構成します。

インターフェイスを使用してこのようにすることができます:

type interface SimpleThingDoer {
   doSimpleThing()
   doAnotherSimpleThing()
}

func doComplexThing(db SimpleThingDoer) {
   db.doSimpleThing()
   db.doAnotherSimpleThing()
}

func (db *sql.DB) doSimpleThing() {
   // standard implementation, that we expect to override
}

func (db ConnexionMySQL) doSimpleThing() {
   // other implemenation
}

これは、クラス階層の古典的なオーバーライドとはまったく異なります。

特に、2番目のレベルから関数の実装を継承する3番目のレベルを直接持つことはできません。

実際には、ほとんどの(直交)インターフェースの使用を終了し、実装の「スーパークラス」がそれらの呼び出しを整理するのではなく、提供された実装で関数に呼び出しを構成させます。

私の経験では、これにより、1レベルよりも深い階層が実質的に存在しなくなります。

多くの場合、他の言語では、概念Aが概念Bの特殊化であることがわかると、クラスBとクラスAをBのサブクラスとして作成することでこの事実を具体化する反射があります。データをプログラムする場合、これが現実であるという原則に基づいて、コード内のオブジェクトの分類法を再現することに時間を費やします。

Goでは、一般的なアルゴリズムを定義して特殊化することはできません。一般的なアルゴリズムを定義し、それが一般的であり、提供されたインターフェース実装で動作することを確認する必要があります。

ロジックが最終的にすべてのレベルを暗示するアルゴリズムに対応するためにコーダーが複雑なハッキングを行っていた階層ツリーの複雑さが増していることに恐怖を感じていたので、たとえ単純なGoロジックに満足していると思いますアプリケーションモデルの概念を単に具体化するのではなく、考える必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.