構文
Haxe ではすべての式が同じレベルです。つまり、式を再帰的に入れ子にできます。例えば foo(if (x == 3) 5 else 8)
と書けます。この例のように、すべての表現は、一定の 型 の値を 戻り値 とします。
リテラル(定数値)
コード中に以下のように数値、文字列、ブール値、null値、正規表現を記述できます :
//整数 0; // Int -134; // Int 0xFF00; // Int(16進表記) //浮動小数点数 123.0; // Float .14179; // Float 13e50; // Float -1e-99; // Float //文字列 "hello"; // String "hello \"world\" !"; // String 'hello "world" !'; // String //真偽値 true; // Bool false; // Bool //null値 null; // Unknown<0> //正規表現 ~/[a-z]+/i; // EReg
null
は特別な値で、どんな型としても使用可能であり、Dynamic
とも異なる挙動を持ちます。詳しくは、型推論で説明します。
演算子
以下の演算子が使用可能です(演算されるのが遅い順):
v = e
:
式e
の値をv
に代入し、式全体はe
を返します。+= -= *= /= %= &= |= ^= <<= >>= >>>=
:
相当する演算の後、代入します。e1 || e2
:
もしe1
がtrue
ならtrue
を返し、そうでなければe2
を評価して返します。e1
・e2
ともBool
でなくてはなりません。e1 && e2
:
もしe1
がfalse
ならfalse
を返し、そうでなければe2
を評価して返します。e1
・e2
ともにBool
でなくてはなりません。e1...e2
:
整数の反復子(イテレータ)を作ります(詳しくは反復子(Iterator)を参照)。== != > < >= <=
:
同じ型の2つの式の間で、通常または物理的な比較を行います。戻り値の型はBool
です。| & ^
:
2つのInt
の式の間で、ビット単位演算を行います。戻り値はInt
です。<< >> >>>
:
2つのInt
の式の間で、ビット単位シフトを行います。戻り値はInt
です。e1 + e2
:
2つの式の間で、たし算をします。戻り値の型は、もしe1
・e2
両方ともInt
の式ならInt
、Int
かFloat
の式ならFloat
、その他の場合はString
です。e1 - e2
:Int
またはFloat
の2つの式の間で、ひき算をします。戻り値の型は、もしe1
・e2
両方ともInt
ならInt
で、その他の場合はFloat
です。e1 * e2
:
かけ算をして、引き算と同様の型の戻り値を返します。e1 / e2
:
わり算をして、戻り値はFloat
です。e1 % e2
:
剰余(余り)を求め、引き算と同様の型の戻り値を返します。
単項演算子
以下の単項演算子が使用可能です :
!
:
ブール値の 否定 です。Bool 値を逆にします。-
:
負の数です。Int
やFloat
値の符号を変えます。++
--
:
式に前置または後置します。前置した場合は、先にインクリメントし、インクリメント後の値を返します。後置した場合は、インクリメント前の値を返してから、インクリメントします。Int
またはFloat
値でのみ使用できます。~
:Int
での1の補数です。ビット単位 NOT を行います。
注意 : ~
は常に 32 ビットの整数で用いられます。従って、Neko での 31 ビットの整数では期待される結果をもたらしません。
丸括弧
演算子の実行の際に、特に優先順位をつけるためには、丸括弧で式をくくります。(e)
の型と値は e
と同じになります。
ブロック
ブロック内では複数の式を処理できます。ブロックの構文は次の通りです :
{ e1; e2; // ... eX; }
ブロックは、そのブロック内の最後の式の値を返します。
例:
{ f(); x = 124; true; }
このブロックは Bool
型で、true
と評価されます。
但し、例外として、空のブロックである{ }
は Void
型と評価されます。
ローカル変数
ローカル変数(局所変数)は、以下の例のように、ブロック内で var
を用いて宣言されます :
{ var x; var y = 3; var z : String; var w : String = ""; var a, b : Bool, c : Int = 0; }
変数は、任意で型と初期値を添えて宣言できます。値が与えられない場合、変数の値はデフォルトで null
となります。型が与えられていない場合は Unknown
型となりますが、その場合でも、厳密に型が付けられています。詳しくは、型推論で説明しています。
複数のローカル変数を同じ var
式で宣言できます。
ローカル変数は、宣言のなされたブロックが終わるまでの間でのみ定義されます。宣言のされたブロックの外からは、アクセスできません。
識別子
変数の識別子があると、以下の順で 解決 がなされます :
- ローカル変数の中で最後に宣言されたもの
- クラスのメンバ(インスタンス)変数(現在のクラスのフィールドと継承されたフィールド)
- 現在のクラスの静的フィールド(クラス変数)
- そのファイル中で宣言されたか、インポート された列挙型の構成子
enum Axis { x; // (1) y; z; } class C { static var x : Int; // (2) var x : Int; // (3) function new() { { // ここでの x は(2)のメンバ変数の this.x を意味します var x : String; // (4) // ここでの x は(4)のローカル変数を意味します } } function f(x : String) { // (5) // ここでの x は(5)の関数の引数を意味します } static function f() { // ここでの x は(2)のクラスの静的変数を意味します } } class D { function new() { // x は (1)の Axis の x を意味します } }
型の識別子 はインポートされたパッケージに従って解決されます。
詳しくは、パッケージ(package)とインポート(import)を参照してください。
フィールドへのアクセス
オブジェクトのフィールドへのアクセスは、伝統的なドット記法で行われます :
o.field
関数呼び出し
関数は丸括弧と実引数を区切るカンマを用いて呼び出します。オブジェクトのメソッドへはドット記法でアクセスできます。
f(1,2,3); object.method(1,2,3);
new
予約語 new
は、クラスのインスタンスを作る式で用いられます。クラス名は必須で、また引数を取れます :
a = new Array(); s = new String("hello");
配列
次のような構文を用いて、値のリストから配列を直接作ることができます :
var a : Array<Int> = [1,2,3,4];
配列型は格納する要素の型を示す 型パラメータ を持つことに注意してください。このようにすることで、型に関するすべての操作は安全になります。このため、1つの配列に格納する要素は、すべて同じ型でなくてはなりません。
配列の値を読み書きするには、次のように伝統的な角括弧記法を用います :
first = a[0]; a[1] = value;
配列の添字は、Int
型でなくてはなりません。
条件分岐(if)
if
式の例を挙げます :
if (life == 0) destroy(); if (flag) 1 else 2;
if
式の一般的な構文は次のとおりです :
if( 条件式 ) 式-1 [else 式-2]
はじめに 条件式
が評価されます。これは Bool
型でなくてはなりません。そして true
であるなら 式-1
が評価され、そうでなければ、式-2
があれば、それが代わりに評価されます。
もし else
がなくて、if
の表現が false
ならば、式全体の型は Void
となります。else
がある場合には、式-1
と 式-2
は同じ型でなければならず、その型が if
式の型となります :
var x : Void = if( flag ) destroy(); var y : Int = if( flag ) 1 else 2;
Haxe での if
は、c言語での三項演算子 a?b:c
の構文に似ています。
例外として、もし(ブロックの途中でのように)if
ブロックが何も値を返さないと想定されている場合は、式-1
と 式-2
は異なる型であることが許され、if
ブロックの型は Void
となります。
ループ(while)
while
は前置条件または後置条件を用いる標準的なループです :
while( 条件式 ) ループ式; do ループ式 while( 条件式 );
例えば、次のようになります :
var i = 0; while( i < 10 ) { // ... i++; }
または do...while
を使って :
var i = 0; do { // ... i++; } while( i < 10 );
if
と同じように、while
ループの 条件式
は Bool
型でなくてはなりません。
もうひとつの実用的な例に、10 から 1 にカウントダウンするループがあります :
var i = 10; while( i > 0 ) { ....... i--; }
繰り返し(for)
for
のループは、伝統的なc言語の for
ループと少し異なります。for
は事実上、反復子(イテレータ) のために使わます。これについては、この文書中で後で紹介します。for
ループの例です :
for( i in 0...a.length ) { foo(a[i]); }
戻り値(return)
関数の終わりより前に関数から抜け出したり、関数から値を返す場合には、return
式を用います :
function odd( x : Int ) : Bool { if( x % 2 != 0 ) return true; return false; }
return
式は、関数が戻り値を必要としない場合、引数なしで使います :
function foo() : Void { // ... if( abort ) return; // .... }
break と continue
この2つの予約語は、for
ループや while
ループから早く抜けたり、ループの次の繰り返しに進む際に役立ちます :
var i = 0; while( i < 10 ) { if( i == 7 ) continue; // この繰り返しをスキップします。 // このブロック内の文はそれ以上処理されず、 // ''while'' の条件式の評価に戻ります。 if( flag ) break; // 繰り返しを早めて終了します。 // ''while'' のループから抜け出し、ループの // 次の文から先に処理は進みます。 }
例外
例外は、局所的ではないジャンプをする方法です。例外を throw
すると、スタック上のどの呼び出し元の関数でも catch
できます。
function foo() { // ... throw new Error("invalid foo"); } // ... try { foo(); } catch( e : Error ) { // 例外の処理 }
異なる型の例外を処理するために、try
の後に複数の catch
ブロックを置くこともできます。これらは宣言された順に試行されます。Dynamic
を catch
すると、すべての例外が catch
されます。
try { foo(); } catch( e : String ) { // この種類のエラーを処理 } catch( e : Error ) { // 別の種類のエラーを処理 } catch( e : Dynamic ) { // その他すべてのエラーを処理 }
一連の 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; }
注意 : 上の例では、1つの case
が 65, 90
となっていますが、これは、2つ(またはそれ以上)のうちいずれかの値 にマッチすることが期待される場合の例で、コンマで列挙を区切ります。
Haxe における switch
は、伝統的な switch
と異なります。すべての case は別個であり、1つの case
の式が処理された後には、switch
のブロックから自動的に抜け出ます。このため、switch
では break
を使うことはできず、また、default
の位置は重要ではありません。
いくつかの プラットフォーム においては、switch
は定数の値(とくに整数の定数)では、スピード向上のため、最適化される場合があります。
switch
は enum
に対する特殊な用法を持ちます。これについては、列挙型(enum)を参照してください
ローカル関数
ローカル(局所的な)関数は、 予約語 function
を用いて宣言しますが、名前を持ちません。 ローカル関数は、定数値の整数や文字列と同じく 値 です :
var f = function() { /* ... */ }; f(); // 関数の呼び出し
ローカル関数は、引数、現在のクラスの静的な変数、関数自身より前に宣言されたローカル変数にアクセス可能です :
var x = 10; var add = function(n) { x += n; }; add(2); add(3); // この時点で x は 15 になっている
しかし、メソッドの中で宣言されたローカル関数は、this
の値にアクセスできません。そのため、me
のようなローカル変数を宣言する必要があります :
class C { var x : Int; function f() { // コンパイル不可 var add = function(n) { this.x += n; }; } function f2() { // コンパイル可 var me = this; var add = function(n) { me.x += n; }; } }
匿名オブジェクト
匿名オブジェクトは、次のように宣言します :
var o = { age : 26, name : "Tom" };
型推論 のために、匿名オブジェクトも厳密に型付けされます。
詳しくは、構造体(匿名オブジェクト)を参照してください。