语法
在Haxe,所有表达式处于同一级别。这意味着你可以递归聚集使用它们不会发生任何问题,例如 foo(if(x == 3) 5 else 8) 是合法的 Haxe 表达式。就像这个例子显示的那样,这意味着所有表达式有一个指定类型的返回值。
常量
下面是可用的一些常量:
0; // Int -134; // Int 0xFF00; // Int 123.0; // Float .14179; // Float 13e50; // Float -1e-99; // Float "hello"; // String "hello \"world\" !"; // String 'hello "world" !'; // String true; // Bool false; // Bool null; // Unknown<0> ~/[a-z]+/i; // EReg : regular expression
你会注意到null在任何类型中是一个特别的值,并且有着动态的行为。这将在后面介绍类型推定(type inference)的时候详细解释。
操作符
以下是按优先级顺序排列的一些Haxe中的操作符:
- 一元操作符(详见下一节)。
e1 % e2:计算e1对e2取模的值,如果e1、e2都是Int类型,则返回一个Int类型, 否则返回Float类型。e1 / e2:两数相除。返回Float类型。e1 * e2:两数相乘。和取模运算返回类型一致。e1 - e2:Int类型或者Float类型相减。和取模运算返回类型一致。e1 + e2:两数相减。返回类型与取模运算返回类型一致。<< >> >>>:在两个Int类型的表达式之间进行移位运算。返回Int类型。| & ^:在两个Int类型的表达式之间进行位运算(或、与、异或)。返回Int类型。== != > < >= <=:在两个具有相同返回类型的表达式之间进行标准的或物理的(physical)比较运算。返回Bool类型。e1...e2:从e1到e2构建一个 IntIter - 详见 Iterators 。e1 && e2:如果e1为false则表达式结果为false,否则计算e2。e1和e2都必须是Bool类型。e1 || e2:如果e1为true则表达式结果为true,否则计算e2。e1和e2都必须是Bool类型。- 以及
+= -= *= /= %= &= |= ^= <<= >>= >>>=:在进行相应的运算后赋值。 v = e:对表达式赋值,返回e。
注意:操作符之间的结合性请参见 这里
一元运算符
下列是可用的一元运算符:
!:布尔取反。 对表达式的Bool值取反。-:负数,改变Int类型和Float类型的值的符号。++和--可以放置在一个变量之前或者之后。当放置在变量之前时,会先对变量进行加一操作然后返回家以后的结果。当放置在变量之后时依然会对变量执行加一操作,但是返回加一之前的值。该操作符适用于Int以及Float类型的变量。~: 返回一个Int类型值的反码(ones-complement)。
注意: ~ 一般适用于32位的整数,所以不会对Neko 31位整数产生预期的效果。
因此这个操作符对于Neko无效。
括号
表达式可以使用括号来指定优先级。 ( e ) 的返回类型与 e 的返回类型保持一致。
语句块(Blocks)
语句块可以被用来执行多条语句。它的语法如下:
{ e1; e2; // ... eX; }
语句块表达式的返回类型和返回值与该语句块的 最后一个表达式 一致。 例如:
{ f(); x = 124; true; }
这个语句块返回类型为 Bool 返回值为 true。
一个例外是空的语句块 { } 返回 Void。
局部变量(Local Variables)
使用 var 可以在语句块中声明局部变量,例如下边这个例子:
{ var x; var y = 3; var z : String; var w : String = ""; var a, b : Bool, c : Int = 0; }
变量在声明的时候可以选择是否指定类型和初始值,如果没有指定初始值变量的值默认为null。如果没有指定变量类型那么该变量的类型为 Unknown 但是依旧是强类型(strickly typed)。关于这一点将会在类型推定(type inference)中介绍。
多个变量可以在一个 var 表达式中声明。
局部变量只在它被声明的语句块中有效,该语句块外无法访问(也就是说Haxe具有词法作用域的特性)。
标识符
当Haxe遇到一个变量时,它会按照以下的优先顺序被解析:
- 局部变量,最后被声明的具有最高优先级
- 类成员(当前类成员和和继承的成员)
- 当前类的静态变量
- 在同一文件中声明的或者被引入(imported)的枚举构造函数(enum constructors)
enum Axis { x; y; z; } class C { static var x : Int; var x : Int; function new() { { // 此处x代表成员变量 this.x var x : String; // 此处x代表局部变量 } } function f(x : String) { // 此处x代表函数参数 } static function f() { // 此处x代表类静态变量 } } class D { function new() { // 此处x代表枚举值 x Axis } }
类型标识符 会根据被引入的包(package)来解析,这一点会在之后讲解。
成员变量访问(Field access)
成员变量访问使用传统的「点」号
o.field
调用
您可以使用括号来执行函数调用,使用逗号来分割参数。您可以使用「点」号来调用对象的方法。
f(1,2,3); object.method(1,2,3);
New操作
关键字 new 被用于创建一个类的实例。执行 new 命令需要提供类名和参数:
a = new Array(); s = new String("hello");
数组(Arrays)
使用下边的语法您可以直接从一列值创建数组:
var a : Array<Int> = [1,2,3,4];
请注意数组类型需要一个 类型参数 来描述在数组中存储的对象的类型。 这样所有在数组上的操作都是类型安全(type-safe)的。作为一个序列,所有在给定数组中的对象必须是同一类型。
多维数组可以使用在声明中嵌套类型参数的方法来创建:
var a : Array<Array<Int>> = [ [1, 2, 3], [4, 5], [6, 7, 8, 9], // 最后的逗号会被忽略 ];
您可以使用传统的括号访问符来读写数组:
first = a[0]; a[1] = value;
数组下标必须是 Int 类型。
If 语句
以下是一些 if 语句的实例:
if (life == 0) destroy(); if (flag) 1 else 2;
以下是 if 语句的一般形式:
if( expr-cond ) expr-1 [else expr-2]
首先 expr-cond 会被计算。它的返回值必须是 Bool 类型。如果计算结果为 true 那么执行 expr-1 ,如果返回 false 且存在 expr-2,expr-2将会被执行。
如果没有 else并且 if 语句的值为 false 那么整个语句的返回类型为 Void。如果有 else,那么 expr-1 和 expr-2 必须具有相同的返回类型,整个语句的类型也会是这个类型:
var x : Void = if( flag ) destroy(); var y : Int = if( flag ) 1 else 2;
在 Haxe 中, if 和C语言中的三元运算符 a?b:c 相似。 如果愿意您也可以使用三元运算符。
var x = ( x < upperBound )? x: upperBound;
一个例外是如果 if 语句不需要返回任何值(比如在一个语句块的中间)那么 expr-1 和 expr-2 的返回类型可以不同,并且 if 语句块的返回类型为 Void。
While 语句
While语句是使用前置或者后置条件的标准循环语句:
while( expr-cond ) expr-loop; do expr-loop while( expr-cond );
举例:
var i = 0; while( i < 10 ) { // ... i++; }
或者使用 do...while :
var i = 0; do { // ... i++; } while( i < 10 );
和 if 语句一样,循环中的 expr-cond 必须是 Bool 类型
另一个例子是从10数到1:
var i = 10; while( i > 0 ) { ....... i--; }
For 语句
For循环与传统的 C语言的 for 循环不同,在Haxe中For循环只能被用于迭代器(Iterators)。
下面是一个For循环的例子:
for( i in 0...a.length ) { foo(a[i]); }
如果迭代器(iterator)是使用 ... 操作符直接创建的且第二个关键字小于或者等于第一个关键字,那么这个循环不会被执行。
如果 ... 操作符是按照上述写法(内联的,直接写在For循环里)小于第一个关键字的第二个关键字将会导致一个编译错误。
Return 语句
return 语句用来提前退出一个函数,或者返回一个值:
function odd( x : Int ) : Bool { if( x % 2 != 0 ) return true; return false; }
如果函数没有要求返回值则 return 语句不需要参数:
function foo() : Void { // ... if( abort ) return; // .... }
Break 和 Continue 语句
这两个关键字中 break 用来提前中断一个 for 或者 while 循环,continue 则用来进入下一轮迭代:
var i = 0; while( i < 10 ) { if( i == 7 ) continue; // skip this iteration. // do not execute any more statements in this block, // BUT go back to evaluating the "while" condition. if( flag ) break; // stop early. // Jump out of the "while" loop, and continue // execution with the statement following the while loop. }
异常处理
异常处理用于“全局”的中断。也就是说你可以 throw 一个异常并且从在栈上的任意被调函数中 catch 它。
function foo() { // ... throw "invalid foo"; } // ... try { foo(); } catch( e : String ) { // handle exception }
为了捕获不同类型的异常在 try 语句之后可以有多个 catch 语句,它们会在被声明的地方执行。捕捉一个 Dynamic 类型的异常意味着捕获所有类型的异常:
try { foo(); } catch( e : String ) { // handle this kind of error } catch( e : Error ) { // handle another kind of error } catch( e : Dynamic ) { // handle all other errors }
除非不需要返回值,否则所有的 try 和 catch 语句都必须拥有相同的返回值类型(和 if 语句一样)。
详见异常处理。
Switch 语句
Switch语句是对同一个值进行多个 if...else if... else if 检测的简便写法:
if( v == 0 ) e1 else if( v == foo(1) ) e2 else if( v == 65 || v == 90 ) e3 else e4;
上边的语句与下边的 switch 语句是等价的:
switch( v ) { case 0: e1; case foo(1): e2; case 65, 90: e3; default: e4; }
注意: 上边的例子中有一个case语句后边写着 "65, 90"。这是用于匹配两个(或者多个)之一的值的例子。不同参数之间使用逗号隔开。
在 Haxe 中的Switch语句与传统的switch语句不同:所有的case语句都是独立的表达式。所以在一个case语句被执行后switch语句会自动退出。所以break语句不能在Switch语句中使用。default 的顺序并不重要。
在一些平台(platforms)中,对常量(特别是整数常量)使用Switch语句会带来一定的性能上的优化。
Switch语句也可以用于具有不同语义的枚举类型(enums)。这一点将会在后续的文档中讲述。
匿名函数(Local function)
匿名函数使用 function 关键字创建,但必须是匿名的。 它们的“值”就好像字符串字面量或者整数字面量一样:
var f = function() { /* ... */ }; f(); // 函数调用
匿名函数可以访问当前类的静态变量或者是在它之前定义的局部变量:
var x = 10; var add = function(n) { x += n; }; add(2); add(3); // now x is 15
但是,在方法中声明的匿名函数不能直接访问 this 变量。如果需要访问 "this" 变量您需要先声明一个局部变量,比如 me :
class C { var x : Int; function f() { // WILL NOT COMPILE var add = function(n) { this.x += n; }; } function f2() { // will compile var me = this; var add = function(n) { me.x += n; }; } }
匿名对象(Anonymous objects)
匿名对象可以使用下面的语法声明:
var o = { age : 26, name : "Tom" };
请注意因为类型推定的存在,所以匿名对象也是强类型的。