ソフトウェアのランダムなトピックをオンラインで読んでいるときに、ダックタイピングという用語に出くわしましたが、完全に理解していませんでした。
「ダックタイピング」とは何ですか?
ソフトウェアのランダムなトピックをオンラインで読んでいるときに、ダックタイピングという用語に出くわしましたが、完全に理解していませんでした。
「ダックタイピング」とは何ですか?
回答:
アイデアは、オブジェクトの既存のメソッドを呼び出すために型を必要としないということです。メソッドが定義されている場合は、それを呼び出すことができます。
名前は、「アヒルのように見え、アヒルのように鳴く場合、それはアヒルです」というフレーズに由来します。
ウィキペディアにはもっと多くの情報があります。
ダックタイピング とは、演算がそのオペランドが満たす必要のある要件を正式に指定するのではなく、与えられたものを使って試すことを意味します。
他の人が言ったこととは異なり、これは必ずしも動的言語や継承の問題に関連しているわけではありません。
タスクの例:Quack
オブジェクトのメソッドを呼び出す。
ダックタイピングを使用しない場合、f
このタスクを実行する関数は、引数が何らかのメソッドをサポートする必要があることを事前に指定する必要がありますQuack
。一般的な方法は、インターフェースの使用です
interface IQuack {
void Quack();
}
void f(IQuack x) {
x.Quack();
}
呼び出しはf(42)
失敗しますが、f(donald)
限りとして働くdonald
のインスタンスであるIQuack
-subtype。
もう1つのアプローチは構造型付けです。ただし、このメソッドQuack()
も正式に指定されているためquack
、事前にそれが原因でコンパイラエラーが発生することを証明できません。
def f(x : { def Quack() : Unit }) = x.Quack()
私たちは書くことさえできました
f :: Quackable a => a -> IO ()
f = quack
型Quackable
クラスがメソッドの存在を保証するHaskellで。
まあ、私が言ったように、アヒルのタイピングシステムは要件を指定せず、何かが機能するかどうかを試すだけです。
したがって、Pythonの動的型システムは常にダック型を使用します。
def f(x):
x.Quack()
場合はf
取得x
支援Quack()
、それは実行時にクラッシュしますない場合は、すべてが、大丈夫です。
しかし、アヒルのタイピングは動的なタイピングをまったく意味していません。実際、非常に人気のある完全に静的なアヒルのタイピングアプローチがあり、要件もありません。
template <typename T>
void f(T x) { x.Quack(); }
この関数はx
、できることを望んでいることをまったく伝えていないQuack
ため、代わりにコンパイル時に試行するだけで、すべてが機能する場合は問題ありません。
def f(x)
の代わりにdef f(IQuack x)
。
質問のセマンティクスの議論はかなり微妙です(そして非常に学術的です)が、ここに一般的な考えがあります:
アヒルのタイピング
(「それがアヒルのように歩き、アヒルのように鳴るなら、それはアヒルです。」- はい!しかし、それはどういう意味ですか?これは例によって最もよく示されます:
ダックタイピング機能の例:
私が魔法の杖を持っていると想像してください。それは特別な力を持っています。杖を振って「ドライブ」と言うと 車に、それでは、それは運転します!
それは他のものに働きますか?わからない:トラックで試してみる。うわー-それも運転する!次に、飛行機、電車、1ウッズで試してみます(これらは、人々がゴルフボールを「ドライブ」するために使用するタイプのゴルフクラブです)。彼らはすべて運転します!
しかし、それはティーカップでうまくいくでしょうか?エラー:KAAAA-BOOOOOOM!それはあまりうまくいきませんでした。====>ティーカップは運転できません!! えっ?
これは基本的にダックタイピングの概念です。これは、購入前の試用 システムです。うまくいけば、すべてが順調です。しかし、失敗した場合、手に残っている手榴弾のように、それはあなたの顔を爆破するでしょう。
つまり、オブジェクトの内容ではなく、オブジェクトが実行できる内容に関心があります。
例:静的型付け言語
オブジェクトが実際に何であるかを懸念していた場合、手品は、事前設定された承認済みのタイプ(この場合は車)でのみ機能しますが、トラック、モペット、トゥクトゥクなど、運転できる他のオブジェクトでは失敗します。私たちの魔法の杖は車でのみ機能することを期待しているため、トラックでは機能しません。
言い換えれば、このシナリオでは、魔法は、オブジェクトがどのように非常に密接なルックスワンドである(それは車です?)ではなく、オブジェクトが何よりも行うことができます(例えば乗用車、トラックなどが運転できるかどうか)。
トラックを運転させる唯一の方法は、何らかの方法で魔法の杖をトラックと車の両方に期待できるかどうかです(おそらく「共通のインターフェースを実装することによって」)。意味がわからない場合は、しばらくは無視してください。
まとめ:重要な持ち帰り
ダックタイピングで重要なのは、オブジェクトが何であるかではなく、オブジェクトが実際に実行できることです。
タイプのオブジェクトを取得してBird
そのwalk()
メソッドを呼び出す単純な関数を設計しているとしましょう。あなたが考えることができる2つのアプローチがあります:
Bird
、のみを受け入れるか、コードがコンパイルされないことを確認する必要があります。誰もが私の機能を使用したい場合は、彼は私が唯一受け入れていることを認識しなければならないBird
のをobjects
を取得し、オブジェクトのwalk()
メソッドを呼び出すだけです。だから、あればobject
缶walk()
、それは私の機能の意志が失敗したことができない場合には、正しいです。したがって、ここではオブジェクトがBird
何か他のものであることは重要ではありません。できることは重要ですwalk()
(これはダックタイピングです)アヒルのタイピングが役立つ場合があることを考慮する必要があります。たとえば、Pythonではアヒルのタイピングが頻繁に使用されます。
ウィキペディアにはかなり詳細な説明があります:
http://en.wikipedia.org/wiki/Duck_typing
ダックタイピングは、特定のクラスまたは特定のインターフェースの実装からの継承ではなく、オブジェクトの現在のメソッドとプロパティのセットが有効なセマンティクスを決定する動的タイピングのスタイルです。
重要な注意点として、ダックタイピングでは、開発者は実際の基本的なタイプではなく、消費されるオブジェクトの部分に関心を持っているようです。
古いイディオムを繰り返す答えがたくさんあります。
それがアヒルのように見え、アヒルのように鳴く場合、それはアヒル
次に、アヒルのタイピングで何ができるかについての説明、または概念をさらに難読化する例について詳しく説明します。
あまり助けにはなりません。
これは、私が見つけたアヒルのタイピングについてのわかりやすい英語の回答での最良の試みです。
ダックタイピングとは、オブジェクトがそれが何であるかによってではなく、何ができるかによって定義されることを意味します。
つまり、オブジェクトのクラス/タイプではなく、オブジェクトに対して呼び出すことができるメソッドと、オブジェクトに対して実行できる操作に関心があります。タイプではなく、何ができるかを気にします。
アヒルのタイピング:
しゃべったり、アヒルのように歩くなら、それはアヒルです
これは通常、拉致と呼ばれます(拉致推論またはレトロダクションとも呼ばれ、より明確な定義だと思います)。
C(結論、私たちは何を参照してください)とR(ルール、私たちが知っている)、私たちが決める/受け入れ/前提とP(前提、プロパティを別の言葉で与えられた事実を)
...医療診断の基本
カモと:C = 歩く、話す、R = アヒルのよう、P = アヒルのよう
プログラミングに戻る:
オブジェクトoにはメソッド/プロパティmp1があり、インターフェース/タイプTに はmp1が必要/定義されています
オブジェクトoにはメソッド/プロパティmp2が あり、インターフェース/タイプTにはmp2が必要/定義されています
...
だから、より簡単に受け入れることよりもMP1をあれば、いくつかの定義を満たしているように任意のオブジェクトに... MP1を表明して...、コンパイラ/ランタイムも大丈夫でなければなりませんoが型であるT
さて、上記の例はそうですか?Duckのタイピングは基本的にまったくタイピングではないのですか?それとも暗黙の型付けと呼ぶべきでしょうか?
言語自体を見ることは役立つかもしれません。それはしばしば私を助けてくれます(私はネイティブの英語を話す人ではありません)。
でduck typing
:
1)この単語typing
は、キーボードでタイプすることを意味するのではなく(私の頭の中で永続的なイメージがそうであったように)、それは「その種類の事物の種類は何か」を決定することを意味します。
2)単語duck
は、その決定がどのように行われるかを表します。「アヒルのように歩く場合、それはアヒルのようです」のように、それは一種の「緩い」決定です。それはアヒルかもしれないしそうでないかもしれないので、それは「ゆるい」ですが、それが実際にアヒルであるかどうかは関係ありません。重要なのは、カモでできること、カモが示す行動を期待できることです。私はそれをパン粉に食べさせることができます、そして、物事は私に向かって行くかもしれません、または私に向かって充電するか、または引き返すかもしれません...
私は一般的な答えを出していないことを知っています。Rubyでは、変数やメソッドの型を宣言していません。すべてが一種のオブジェクトです。したがって、ルールは「クラスはタイプではない」です
Rubyでは、クラスは決して(大丈夫、ほとんど決して)タイプではありません。代わりに、オブジェクトのタイプは、そのオブジェクトが実行できることによってさらに定義されます。Rubyでは、これをアヒル型付けと呼びます。オブジェクトがアヒルのように歩き、アヒルのように話す場合、通訳者はそれをアヒルのように喜んで扱います。
たとえば、曲情報を文字列に追加するルーチンを作成しているとします。C#またはJavaのバックグラウンドを使用している場合は、次のように書きたくなるでしょう。
def append_song(result, song)
# test we're given the right parameters
unless result.kind_of?(String)
fail TypeError.new("String expected") end
unless song.kind_of?(Song)
fail TypeError.new("Song expected")
end
result << song.title << " (" << song.artist << ")" end
result = ""
append_song(result, song) # => "I Got Rhythm (Gene Kelly)"
Rubyのダックタイピングを採用すれば、はるかに簡単なものを書くことができます。
def append_song(result, song)
result << song.title << " (" << song.artist << ")"
end
result = ""
append_song(result, song) # => "I Got Rhythm (Gene Kelly)"
引数の型を確認する必要はありません。<<(結果の場合)またはタイトルとアーティスト(曲の場合)をサポートする場合、すべてが機能します。そうでない場合、メソッドはとにかく例外をスローします(型をチェックした場合と同じように)。しかし、チェックがなければ、メソッドは突然より柔軟になります。配列、文字列、ファイル、または<<を使用して追加するその他のオブジェクトを渡すことができますが、これは機能します。
アヒルのタイピングはタイプのヒントではありません!
基本的に、「ダックタイピング」を使用するために、特定のタイプではなく、共通のインターフェースを使用して、より広い範囲のサブタイプ(継承についてではなく、サブタイプを意味するとき、同じプロファイルに適合する「もの」を意味する)をターゲットにします。
情報を保存するシステムを想像できます。情報を読み書きするには、何らかのストレージと情報が必要です。
ストレージのタイプには、ファイル、データベース、セッションなどがあります。
インターフェースは、ストレージタイプに関係なく利用可能なオプション(メソッド)を通知します。つまり、この時点では何も実装されていません。言い換えれば、インターフェイスは情報を格納する方法について何も知りません。
すべてのストレージシステムは、まったく同じメソッドを実装することにより、インターフェイスの存在を認識している必要があります。
interface StorageInterface
{
public function write(string $key, array $value): bool;
public function read(string $key): array;
}
class File implements StorageInterface
{
public function read(string $key): array {
//reading from a file
}
public function write(string $key, array $value): bool {
//writing in a file implementation
}
}
class Session implements StorageInterface
{
public function read(string $key): array {
//reading from a session
}
public function write(string $key, array $value): bool {
//writing in a session implementation
}
}
class Storage implements StorageInterface
{
private $_storage = null;
function __construct(StorageInterface $storage) {
$this->_storage = $storage;
}
public function read(string $key): array {
return $this->_storage->read($key);
}
public function write(string $key, array $value): bool {
return ($this->_storage->write($key, $value)) ? true : false;
}
}
だから今、あなたは情報を読み書きする必要があるたびに:
$file = new Storage(new File());
$file->write('filename', ['information'] );
echo $file->read('filename');
$session = new Storage(new Session());
$session->write('filename', ['information'] );
echo $session->read('filename');
この例では、StorageコンストラクタでDuck Typingを使用します。
function __construct(StorageInterface $storage) ...
それが役に立てば幸い;)
私は自分の方法で有名な文を理解しようとします:「Pythonはオブジェクトが本当のカモであるかどうかを気にしません。気になるのは、オブジェクトが最初に「ガク」、次に「カモのよう」であるかどうかです。」
良いウェブサイトがあります。http://www.voidspace.org.uk/python/articles/duck_typing.shtml#id14
著者は、ダックタイピングにより、独自の内部データ構造を持つ独自のクラスを作成できることを指摘しましたが、通常のPython構文を使用してアクセスします。