LoginSignup
21
12

More than 5 years have passed since last update.

Dartのオブジェクトは関数だ

Last updated at Posted at 2014-07-21

現在よく使われているいろいろな言語と同様に、Dartの関数はファーストクラスのオブジェクトである。さらに、Dartにおいては逆にオブジェクトが関数になることができる。

次の2つのコードは全く同じ意味を持つ。

1つ目はオブジェクトの関数を呼び出す方法

class Caller {

  String call(String str) {
    return str;
  }
}

main() {
  var caller = new Caller();
  print(caller.call("laco")); // laco
}

2つ目はオブジェクトを関数として呼び出す方法

class Caller {

  String call(String str) {
    return str;
  }
}

main() {
  var caller = new Caller();
  print(caller("laco")); // laco
}

特別なメソッド: call()

Dartではcall()という名前のメソッドを定義したクラスのオブジェクトは関数になる。引数は自由に設定できるが、オーバーロードはないので一つしかcall()は定義できない。

このcall()が定義されたクラスは「関数のように振る舞う」のではなく「関数そのもの」なので、以下のような結果になる

class A{
  void call(){
  }
}

class B{
  void calls(){
  }
}

main(){
  print(new A() is Function); //true
  print(new B() is Function); //false
}

関数としてオブジェクトを渡す

Dartではtypedefを用いて、独自の関数型を作る。C#をやったことがある方ならDart版delegateだと思っていい。例えばStringを引数に取り、Stringを返す関数は以下のように定義する。

/**
 * The function of [String] -> [String] converter
 */
typedef String StringConverter(String seed);

定義した関数型は次のように用いることが出来る。

String convert(StringConverter func, String seed) {
  return func(seed);
}

このStringConverter型は、『Stringを引数により、実行するとStringを返す』関数ならなんでも受け入れることが出来るので、先ほどのcall()と合わせると以下のように関数としてオブジェクトを渡すことができる。継承などは一切必要ない。

class TripleCaller {

  String call(String str) {
    return "${str}" * 3;
  }
}

/**
 * The function of [String] -> [String] converter
 */
typedef String StringConverter(String seed);

String convert(StringConverter func, String seed) {
  return func(seed);
}

main() {
  var laco = new TripleCaller();
  print(convert(laco, "laco")); // lacolacolaco
}

もちろん関数型など作らずとも次のように書いてもよい。全ては実行時に解決される。

String convert(Function func, String seed) {
  return func(seed);
}
21
12
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
12