Haxe入門 / 2.6 Function Type

目次に戻る

2.6 Function type 関数型

(Anonymous structureの続きは後回し。)

関数型(関数の型)はHaxeのユーザはあんまり気にすること無いけど、いろんなとこにホントはあるんだよ(超意訳)。関数型は$typeを使えば確認できて、これ使うと式の型がコンパイル時に出力されます。

class FunctionType {
    static public function main() {
        $type(test); // i : Int -> s : String -> Bool
        $type(test(1, "foo")); // Bool
    }
    
    static function test(i:Int, s:String):Bool {
        return true;
    }
}

出力

Warning : i : Int -> s : String -> Bool

Warning : Bool

$typeの出力は警告扱いのようだ。

test関数の宣言と、$typeの出力は似てるけどちょっと違いますね。$typeの出力の方は

  • 関数の引数i:Ints:Stringはカンマ,じゃなくてアロー->で区切られてます。
  • 関数の返値の型は、もう1つの->の後に表示されます。

どちらの記法でもtest関数が第1引数の型にIntを、第2引数の型にStringをとり、返り値の型はBoolであることはなんとなくわかります。

もし関数呼び出し(test(1,"foo"))が$typeに渡されると、Haxeは引数の型をチェックして、test関数の返り値の型であるBoolを出力します。

関数の引数に関数型を取る場合は()で囲って表示されます。例えば

Int -> (Int -> Void) -> Void

みたいに。この例だと、第1引数の型はInt、第2引数の型は「Int型を引数にとりVoid型を返す関数」の型、そして返り値の型はVoidですね。具体的にはこういうコードです。

class FunctionType {
    static public function main() {
        $type(foo); 
        foo(3,bar);
    }

    static public function foo(x: Int, f: (Int->Void)) {
        f(x);
    }

    static public function bar(y: Int) {
        trace(y);
    }
}

2.6.1 Optional Arguments オプショナル引数

オプショナル引数を使うと関数に渡す引数を省略できる。引数の識別子の先頭に?(question mark)を付けて宣言する。

class OptionalArguments {
  static public function main() {
    $type(test); // ?i : Int -> ?s : String -> String
    trace(test()); // i: null, s: null
    trace(test(1)); // i: 1, s: null
    trace(test(1, "foo")); // i: 1, s: foo
    trace(test("foo")); // i: null, s: foo
  }

  static function test(?i:Int, ?s:String) {
    return "i: " +i + ", s: " +s;
  }
}

test関数は2つのオプショナル引数、つまりInt型の変数iString型の変数sを持つ。これは関数の型から直接とれる(3行目)。上の例だとtest関数は4回よばれてそれぞれ返り値を出力してる。

  1. ひとつ目は引数なしで呼び出し。
  2. 2つ目は1だけを引数に渡して呼び出し。
  3. 3つ目は1"foo"を省略せずに呼び出し。
  4. 4つ目は"foo"だけを引数に渡して呼び出し。

出力結果を見ると、引数が省略された場合はnullとして扱われてる。これはつまり、引数にnull値を与えられるってこと。静的型言語がターゲットの場合、基本型にはnullを入れることができないことに注意。nullを渡せられるのは?をつけているから。この話はNullabilityでも触れている。

最初の3つの例は直感的に多くの人は理解できるはず。でも4つ目に対しては驚く人もいるんじゃないだろうか。 この場合、"foo"Intに代入できないが後ろに適合する型Stringがあるので、オプショナル引数のIntをスキップできる。

2.6.2 Default values デフォルト値

Haxeでは引数に定数のデフォルト値を使うことができる。

class DefaultValues {
  static public function main() {
    // ?i : Int -> ?s : String -> String
    $type(test);
    trace(test()); // i: 12, s: bar
    trace(test(1)); // i: 1, s: bar
    trace(test(1, "foo")); // i: 1, s: foo
    trace(test("foo")); // i: 12, s: foo
  }

  static function test(i = 12, s = "bar") {
    return "i: " +i + ", s: " +s;
  }
}

この例は[オプショナル引数]で出てきたものとよく似てるけど、12"bar"が関数の引数isに 割り当てられるとこだけ違う。呼び出し時に引数が省略された場合nullじゃなくてデフォルト値を使う。

Haxeのデフォルト値は型の一部ではないし、呼び出し側で置換されるわけでもない(関数がインライン化されていなければ。これはよりtypicalなアプローチだ。 いくつかのターゲットでは、コンパイラは引数が省略された場合にまだnullを渡すかもしれない。その場合はこんなコードを関数内に挿入する。

static function test(i = 12, s = "bar") {
    if (i == null) i = 12;
    if (s == null) s = "bar";
    return "i: " +i + ", s: " +s;
}

This should be considered in performance-critical code where a solution without default values may sometimes be more viable. (<= 訳せない)

目次に戻る