Dart では、クラスの一部として宣言されたインスタンス メソッドと、他の関数 (クロージャーや静的関数など) との間に違いがあります。
にアクセスできるのは、インスタンス メソッドだけです (コンストラクターを除く) this。概念的には、オブジェクトではなくクラス記述の一部です。つまり、メソッド呼び出しを行うと、o.foo()Dart は最初に のクラス タイプを抽出しoます。次に、クラスの説明で を検索しますfoo(必要に応じてスーパー クラスを再帰的に調べます)。最後に、見つかったメソッドをthisset に適用しoます。
オブジェクト ( o.foo()) でメソッドを呼び出すことができることに加えて、バインドされたクロージャーを取得することもできます: o.foo(呼び出しの括弧なし)。ただし、これは非常に重要です。この形式は、 の構文糖衣にすぎません(<args>) => o.foo(<args>)。つまり、これはo呼び出しをキャプチャしてインスタンス メソッドにリダイレクトする新しいクロージャを作成するだけです。
このセットアップ全体には、いくつかの重要な結果があります。
インスタンス メソッドを切り離して、バインドされたクロージャを取得できます。の結果o.fooは自動的に にバインドされoます。自分でバインドする必要はありません (ただし、別のインスタンスにバインドする方法もありません)。これは、あなたの例ではone.getMyIdうまくいく方法です。実際には次のクロージャを取得しています:() => one.getMyId()代わりに。
メソッドをオブジェクトに追加または削除することはできません。クラスの説明を変更する必要がありますが、これは (意図的に) サポートされていません。
var f = o.foo;常に新鮮なクロージャーを取得することを意味します。これは、このバインドされたクロージャをハッシュテーブルのキーとして使用できないことを意味します。たとえば、各register(o.foo)o.foounregister(o.foo)が異なるため、次の場合はおそらく機能しません。これは、 を試すことで簡単に確認できますprint(o.foo == o.foo)。
あるオブジェクトから別のオブジェクトにメソッドを転送することはできません。インスタンス メソッドにアクセスしようとしても、それらは常にバインドされます。
あなたの例を見る:
print('one ${caller(one.getMyId)}'); //one 1
print('two ${caller(two.getMyId)}'); //two 2
print('one ${callerJustForThree(one.getMyId)}'); //NoSuchMethod Exception
これらの行は次と同等です。
print('one ${caller(() => one.getMyId())}');
print('two ${caller(() => two.getMyId())}');
print('one ${callerJustForThree(() => one.getMyId())}';
内部callerJustForThree:
callerJustForThree(fn){
var three = new IDable(3);
three.fn();
}
指定された引数fnは完全に無視されます。最後の行で実行すると、Dart は(これは)three.fn()のクラス記述を見つけ、その中を検索します。見つからないため、フォールバックを呼び出します。引数は無視されます。threeIDablefnnoSuchMethodfn
いくつかの引数に応じてインスタンス メンバーを呼び出したい場合は、最後の例を次のように書き換えることができます。
main() {
...
callerJustForThree((o) => o.getMyId());
}
callerJustForThree(invokeIDableMember){
var three = new IDable(3);
invokeIDableMember(three);
}