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:Int
とs: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
型の変数i
とString
型の変数s
を持つ。これは関数の型から直接とれる(3行目)。上の例だとtest
関数は4回よばれてそれぞれ返り値を出力してる。
- ひとつ目は引数なしで呼び出し。
- 2つ目は
1
だけを引数に渡して呼び出し。 - 3つ目は
1
と"foo"
を省略せずに呼び出し。 - 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"
が関数の引数i
とs
に
割り当てられるとこだけ違う。呼び出し時に引数が省略された場合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. (<= 訳せない)