函数类型与 单形(第2.9节) 都是一个类型,尽管他们无处不在,但是这两种类型都被很好的隐藏了起来。我们可以使用 一个特殊的 Haxe 标识符 $type
来使得隐藏其后类型浮出水面,它可以在编译时输出它所持表达式的类型:
class Main {
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;
}
}
第一条 $type
表达式的输出与 test
的函数声明十分相似,同时也有微妙的区别:函数参数被特殊的箭头符号 ->
而不是逗号 ,
所分隔,且函数返回类型出现在结尾的另一个 ->
符号之后。
不论哪个记法,很明显,函数 test
接受第一个 Int 类型的参数,第二个 String 类型的参数,并返回一个 Bool 类型值。如果调用这个函数,例如 test(1,"foo")
,并将其放在第二个 $type
语句中,Haxe 类型检查器将会检查 1
是否可以被赋值到 Int
类型参数,然后检查 "foo"
是否可以被赋值到 String
类型参数,检查通过之后函数调用的结果就会和 test
函数返回值的类型相同,即,一个 Bool
类型。
如果一个函数类型有其它函数类型的参数或者返回值,则可以使用括号对它们进行正确的分组。例如,Int->(Int->Void)->Void
表示一个函数,第一个参数为 Int 类型,第二个参数是函数 Int->Void
类型,返回 Void
。
可选参数通过在参数标识符前面前置一个问号 ?
来声明:
class Main {
static public function main() {
// ?i : Int -> ?s : String -> String
$type(test);
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
有两个可选参数:Int 类型的 i
和 String 类型的 s
。这在第3行的函数类型输出直接反映出来。这个例子程序调用了4次 test
,并打印出它的返回值:
- 第一次调用不带任何参数
- 第二次调用带有一个单独的参数
1
- 第三次调用带了两个参数
1
和 "foo
" - 第四次调用只有单独的参数 “
foo
”
输出内容显示,函数调用中被省略的可选参数的值为 null
。这意味着这些参数的类型必须能够接受 null
作为其值,这个问题在 为空性(第2.2节) 中详细讨论。Haxe 编译器会确保当编译至 静态目标平台(第2.2节)时,基本类型的可选参数被推断为Null<T>
使得其成为一个 “可空的” 类型。
前三个调用非常直观,第四个调用可能显得有些意外:如果当前位置提供的值可以被赋值给下一个位置的参数时,则允许跳过可选参数直接赋值给下一个位置的参数。
补充:跳过可选参数的规则是可传递的,比如
static function test(?i:Int, ?f:Float, ?s:String)
{
trace(s);
}
//当调用 test("foo"); 时将会输出 “foo”
Haxe 允许通过分配一个常量值来为参数提供默认值,:
class Main {
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;
}
}
这个示例和前面 可选参数(第2.6.1节) 中的非常相似,唯一的区别是函数的参数 i
和 s
分别被赋值为 12
和 “bar
”。效果为以默认值取代 null
,可以在调用时省略某个参数。Haxe 中的默认值并不是类型的一部分,而且不能在调用时更改函数的默认值(意指只应用于当次调用,而不会改变函数的默认值定义。除非函数是 内联(第4.4.2节) 的,被认为是一个比较典型的处理)。在一些目标语言中,编译器仍可能会传递 null
值作为省略的参数值,生成类似于下面所示的代码到函数中:
static function test(i = 12, s = "bar") {
if (i == null) i = 12;
if (s == null) s = "bar";
return "i: " +i + ", s: " +s;
}
在对性能有要求的代码中这个问题需要被考虑到,因为没有默认值的解决方案有时可能更可行。