18

メンバーを宣言するときにインターフェイスを指定できますか?

この質問についてしばらく考えた後、静的ダック型の言語が実際に機能する可能性があることに気づきました。定義済みクラスをコンパイル時にインターフェイスにバインドできないのはなぜですか? 例:

public interface IMyInterface
{
  public void MyMethod();
}

public class MyClass  //Does not explicitly implement IMyInterface
{
  public void MyMethod()  //But contains a compatible method definition
  {
    Console.WriteLine("Hello, world!");
  }
}

...

public void CallMyMethod(IMyInterface m)
{
  m.MyMethod();
}

...

MyClass obj = new MyClass();
CallMyMethod(obj);     // Automatically recognize that MyClass "fits" 
                       // MyInterface, and force a type-cast.

そのような機能をサポートする言語を知っていますか? Java または C# で役に立ちますか? 何らかの形で根本的に欠陥がありますか?MyClass をサブクラス化してインターフェイスを実装したり、Adapter デザイン パターンを使用して同じことを達成したりできることは理解していますが、これらのアプローチは不必要なボイラープレート コードのように思えます。

4

15 に答える 15

19

この質問に対するまったく新しい答え、Go にはまさにこの機能があります。私はそれが本当にクールで賢いと思います(実際にどのように機能するかを見ることに興味があります)そしてそれを考えたことを称賛します.

公式ドキュメントに記載されているように (Tour of Go の一部として、コード例とともに) :

インターフェイスは暗黙的に実装されます

型は、そのメソッドを実装することによってインターフェイスを実装します。明示的な意図の宣言も、「implements」キーワードもありません。

暗黙的なインターフェースは、インターフェースの定義をその実装から切り離します。これにより、事前の取り決めなしで任意のパッケージに表示される可能性があります。

于 2009-11-11T20:16:44.493 に答える
14

C++ でテンプレートを使用するのはどうですか?

class IMyInterface  // Inheritance from this is optional
{
public:
  virtual void MyMethod() = 0;
}

class MyClass  // Does not explicitly implement IMyInterface
{
public:
  void MyMethod()  // But contains a compatible method definition
  {
    std::cout << "Hello, world!" "\n";
  }
}

template<typename MyInterface>
void CallMyMethod(MyInterface& m)
{
  m.MyMethod();  // instantiation succeeds iff MyInterface has MyMethod
}

MyClass obj;
CallMyMethod(obj);     // Automatically generate code with MyClass as 
                       // MyInterface

このコードを実際にコンパイルしたことはありませんが、実行可能であり、元の提案された (しかし動作しない) コードのかなり些細な C++ 化であると思います。

于 2008-11-23T21:21:52.527 に答える
10

要点がわかりません。クラスがインターフェイスを実装し、それを処理したことを明示しないのはなぜですか? インターフェースを実装することで、このクラスはインターフェースが定義する方法で動作することになっていることを他のプログラマーに伝えることができます。メソッドに同じ名前と署名を付けただけでは、設計者の意図がそのメソッドで同様のアクションを実行することであったという保証はありません。そうかもしれませんが、なぜそれを解釈 (および誤用) のために放置するのでしょうか?

動的言語でこれをうまく「回避」できる理由は、言語自体よりもTDDに関係しています。私の意見では、言語が、コードを使用/表示する他の人にこの種のガイダンスを提供する機能を提供する場合は、それを使用する必要があります。それは実際に明瞭さを改善し、いくつかの余分な文字の価値があります. これを行うためのアクセス権がない場合、アダプターは、インターフェイスが他のクラスにどのように関連するかを明示的に宣言するという同じ目的を果たします。

于 2008-11-14T03:09:41.767 に答える
10

静的型付け言語は、定義上、実行時ではなくコンパイル時に型をチェックします。上記のシステムの明らかな問題の 1 つは、実行時ではなく、プログラムのコンパイル時にコンパイラが型をチェックすることです。

これで、プログラマーが型を明示的に宣言するのではなく、型を派生できるように、コンパイラーにさらにインテリジェンスを組み込むことができます。コンパイラは、それがメソッドを実装していることを確認し、それに応じてこのケースを処理できる場合があります。インターフェイスを明示的に宣言する必要はありません (提案されているように)。このようなコンパイラはHindley-Milnerなどの型推論を利用できます。MyClassMyMethod()

もちろん、Haskell のような静的に型付けされた言語の中には、あなたが提案したものと同様のことをすでに行っているものがあります。Haskell コンパイラは、(ほとんどの場合) 型を明示的に宣言しなくても型を推論できます。しかし明らかに、Java/C# にはこの機能がありません。

于 2008-11-14T03:37:54.033 に答える
9

F# は静的なダック タイピングをサポートしていますが、注意点があります。メンバー制約を使用する必要があります。詳細については、このブログ エントリを参照してください。

引用されたブログの例:

let inline speak (a: ^a) =
    let x = (^a : (member speak: unit -> string) (a))
    printfn "It said: %s" x
    let y = (^a : (member talk: unit -> string) (a))
    printfn "Then it said %s" y

type duck() =
    member x.speak() = "quack"
    member x.talk() = "quackity quack"
type dog() =
    member x.speak() = "woof"
    member x.talk() = "arrrr"

let x = new duck()
let y = new dog()
speak x
speak y
于 2008-11-23T20:47:43.810 に答える
4

ML ファミリーのほとんどの言語は、推論と制約付き型スキームを備えた構造型をサポートしています。これは、元の質問で「静的なダックタイピング」というフレーズが意味する可能性が最も高い言語設計者の専門用語です。

このファミリーで最も人気のある言語には、Haskell、Objective Caml、F#、および Scala が含まれます。もちろん、あなたの例に最も近いのは Objective Caml です。あなたの例の翻訳は次のとおりです。

open Printf

class type iMyInterface = object
  method myMethod: unit
end

class myClass = object
  method myMethod = printf "Hello, world!"
end

let callMyMethod: #iMyInterface -> unit = fun m -> m#myMethod

let myClass = new myClass

callMyMethod myClass

注: 使用した名前のいくつかは、OCaml の識別子ケース セマンティクスの概念に準拠するように変更する必要がありますが、それ以外は非常に単純な変換です。

また、関数内の型注釈もクラス型callMyMethodの定義も厳密には必要ないことに注意してください。iMyInterfaceObjective Caml は、型宣言がまったくなくても、例のすべてを推論できます。

于 2009-10-24T03:28:03.177 に答える
2

Scala の構造型は、このようなことを行います。

Scalaで静的にチェックされた「ダックタイピング」を参照してください

于 2008-12-28T23:05:10.223 に答える
2

Crystalは静的なダック型言語です。

def add(x, y)
  x + y
end

add(true, false)

を呼び出すと、次のaddコンパイル エラーが発生します。

Error in foo.cr:6: instantiating 'add(Bool, Bool)'

add(true, false)
^~~

in foo.cr:2: undefined method '+' for Bool

  x + y
    ^
于 2016-05-31T22:53:06.613 に答える
2

Boo は間違いなく静的なダック型言語です: http://boo.codehaus.org/Duck+Typing

抜粋:

Boo は、Java や C# のような静的に型付けされた言語です。これは、boo アプリケーションが、.NET や Mono の他の静的型付け言語でコーディングされたものとほぼ同じ速度で実行されることを意味します。しかし、静的に型付けされた言語を使用すると、場合によっては必要な型宣言 ("x as int" など) や、必要な型キャスト (「x as int」など) や必要な型キャスト (「鋳造タイプ)。Boo の型推論のサポートと、最終的にはジェネリックがここで役立ちますが...

場合によっては、静的型付けによって提供されるセーフティ ネットを放棄することが適切です。メソッド シグネチャについてあまり気にせずに API を調べたいだけかもしれませんし、COM オブジェクトなどの外部コンポーネントと対話するコードを作成しているかもしれません。いずれにせよ、選択は私ではなくあなたのものであるべきです。

object、int、string などの通常の型に加えて、boo には「duck」と呼ばれる特別な型があります。この用語は、Ruby プログラミング言語のダック タイピング機能 (「アヒルのように歩き、アヒルのように鳴く場合、それはアヒルに違いない」) に触発されています。

于 2008-11-14T03:38:23.173 に答える
1

Visual Basic 9 のプレリリース デザインでは、動的インターフェイスを使用した静的ダック タイピングがサポートされていましたが、予定どおりに出荷するために*機能が削除されました。

于 2008-11-14T03:36:18.373 に答える
0

Mixins または Traits のように聞こえます:
http://en.wikipedia.org/wiki/Mixin
http://www.iam.unibe.ch/~scg/Archive/Papers/Scha03aTraits.pdf

于 2008-12-28T22:55:54.623 に答える
0

私のプログラミング言語Heronの最新バージョンでは、と呼ばれる構造サブタイピング強制演算子を介して同様のものをサポートしていますas。したがって、代わりに:

MyClass obj = new MyClass();
CallMyMethod(obj);

あなたは次のように書くでしょう:

MyClass obj = new MyClass();
CallMyMethod(obj as IMyInterface);

あなたの例と同じように、この場合MyClassは明示的に実装する必要はありませんが、実装IMyInterfaceした場合、キャストは暗黙的に発生し、as演算子は省略できます。

この記事では、明示的な構造的サブタイピングと呼んでいる手法についてもう少し詳しく書きました。

于 2009-12-22T20:23:26.283 に答える