Dartの現在の言語仕様(Language Specification)のバージョンは0.10です。言語仕様の最新版は、「Language Specification | Dart: Structured web apps」で公開されています。
文法事項は大きく変わることもありますから、ここではちょっとしたプログラムを作成するのに必要な部分だけ紹介をします。また、プログラミング言語Javaを知っていれば説明がなくても分かると思われる点は説明していませんので、あらかじめご了承ください。
Dartはmain関数からプログラムが開始します。先ほど作成したhello.dartプログラムを見てみましょう。「void main() {}」がmain関数で、「Hello, Dart!」という文字列を出力する処理が関数の中に記述されています。printはコンソール画面へ文字列を出力する関数で、あらかじめ用意されています。
void main() { print('Hello, Dart!'); }
Dartでは文字列リテラルを指定する方法がいくつかあります。代表的なものは次のとおりです。
例を見ながら説明すると分かりやすいでしょう。1.の例としては「'Hello, Dart!'」があります。改行したいときは「'Hello, \nDart!'」のようにします。「\n」は改行コードを表します。
また、「\n」を改行コードではなく文字として表示したい場合は、「@'Hello, \nDart!'」とします。複数行となる文字列リテラルを指定したいときもあります。そのときは次のようにします。
'''Hello, World!'''
「'」ではなく「"」を使うこともできます。
次にhelloweb.dartを見てみましょう。最初にWebアプリで必要なライブラリ「dart:html」をインポートしています。Dartプログラムでは暗黙のうちに「dart:core」のライブラリがインポートされますが、それ以外のライブラリは明示的に指定が必要です。どんなライブラリがあるかの詳細については、「Dart API Reference / Dart API Reference」で公開されているAPIを参照してください。
#import('dart:html');
Webアプリでもmain関数から起動される点は同じです。中の処理を説明します。
Dartでは、「var」を使って変数を宣言できます。ここでは変数「elem」を宣言しています。「query」関数を使うと、HTMLに記述された要素にアクセスができます。「#text」を引数で指定することにより、helloweb.htmlで「id="text"」と指定されている<div>要素を取得できます。これを変数elemへ代入しています。
var elem = query('#text');
次の処理では、div要素のtext属性へ文字列「Hello, Dart!」を代入しています。この結果、Dartiumで表示されるHTMLのドキュメントモデルが更新されます。
elem.text = 'Hello, Dart!';
Dartでは、関数をトップレベルで宣言できるので、helloweb.dartを次のように記述することもできます。ここでは「updateText」関数を用意しています。また、渡された「s」の値へ「"message: "」という文字列を付けて表示する処理をしています。
#import('dart:html'); void main() { final s = 'Hello, Dart!'; // ↑ final String s = 'Hello, Dart!';でもよい updateText(s); } void updateText(var s) { // ↑ void updateText(String s) でもよい var elem = query('#text'); elem.text = 'message: ${s}'; /* ここでは String Interpolation を使っている */ }
値を変更しない変数については「final」を付けます。Dartでは変数を宣言するときにはvarを使うと説明をしましたが、データ型を指定して変数宣言もできます。「final String s」のように変数sに対してString型も指定できます。Dartのデータ型はコンパイル時に型チェックさせたい場合に指定すればよく、取りあえず動けばよいというコードを書いているときはvarを使っておく方法が取れます。
ちなみに、データ型にはnum、int、double、bool、String、List、Mapといったものがあります。詳細は仕様書や「Dart API Reference / Dart API Reference」を参照してください。
プログラム中の「'message: ${s}'」は、「String Interpolation」機能を使っています。文字列リテラルの中に式を埋め込めで「${式}」の評価結果が文字列に埋め込まれます。
コメントについては、「//」を説明しました。複数行のコメントを記述したい場合は「/*」と「*/」で囲みます。Dartはドキュメント用のコメントもサポートしています。それを付けたい場合は「/**」と「*/」で囲みます。
Dartの関数は、いろいろな書き方ができます。次のプログラムでは「concat0」「concat1」「concat2」といった関数を用意しています。どれも文字列を連結して結果を文字列で返す関数です。「{ return x; }」を略した表現として、「=> x;」を使えます(concat1)。また、型の指定も省略できます(concat2)。
String concat0(String x, String y) { return "$x $y"; } String concat1(String x, String y) => "$x $y"; concat2(x, y) => "$x $y"; void main() { print(concat0('a', 'b')); print(concat1('a', 'b')); print(concat2('a', 'b')); }
省略可能なパラメータの指定もできます。「[」と「]」で囲みます。次の例では関数fのパラメータzは省略可能なので、「f('a', 'b')」とパラメータを2つにすることも、「f('a', 'b', 'c')」とパラメータを3つにすることもできます。省略されると、zの値はnullとなります。
String f(String x, String y, [String z]) { if (z != null) return '$x $y $z'; return '$x $y'; } void main() { print(f('a', 'b')); // a bが表示される print(f('a', 'b', 'c')); // a b cが表示される }
処理の制御については、条件分岐処理(if、switch)、反復処理(for、while)はもちろんできます。次の例では、再帰的関数sumを使って1からnまでの整数の和を求めています。
int sum(int n) { if (n == 1) return 1; else return(n + sum(n-1)); } void main() { print(sum(5)); // 15 }
同じプログラムをforを使って実装すると次のようになります。
nt sum(int n) { int x = 0; for (int i=1; i<=n ; i++) { x += i; } return x; } void main() { print(sum(5)); // 15 }
Dartでは「[1, 2, 3, 4, 5, 6]」といった値はList型です。List型の値においては、各要素に対して処理をするには、カウンター変数iを用意して、各要素を走査するおなじみの方法が使えます。
もっと簡単に、for-inを使ったり、forEachメソッドを使ったりする方法もあります。for-inでは各要素へアクセスするための変数eを宣言して、それを処理で使っていることが、見れば分かるはずです。forEachメソッドを使う方法は、各要素に対して実行する関数(ここでは「(e)=>print(e)」)を渡しています。
void main() { List values = [1, 2, 3, 4, 5, 6]; for (int i=0 ; i<values.length ; i++) { print(values[i]); } for (var e in values) print(e); // for-in values.forEach((e)=>print(e)); // forEach }
これだけの説明では文法事項を全然網羅できていませんが、ここまでの説明で大体Dartプログラムの様子は分かったのではないでしょうか。クラスベースといいつつ、ClassやInterfaceについてはまだ説明をしていませんが、それらについてはもう少し具体的なアプリを作りながら理解をすることにします。
ただし関数については、まだ説明が足りないので、もう少しお付きあいください。
Dartでは関数は第1級クラスなので、関数を引数へ渡したり、変数へ代入できます。
次の例では、isEvenという関数を、List型変数valuesのfilterメソッドへ渡しています。filterメソッドは各要素について渡された関数を適用してtrueとなる値だけを要素として持つList型の値を返します。パラメータを渡すときに略式の関数も指定できます。
bool isEven(num n) => n%2==0; void main() { var values = [1, 2, 3, 4, 5, 6]; var evenValues = values.filter(isEven); print(evenValues); // [2, 4, 6] }
filterメソッドへ奇数を判定する関数を渡す場合は次のようにします。こちらを使った場合は、oddValuesは[1, 3, 5]となります。
var oddValues = values.filter((num n)=>n%2==1);
Dartはクロージャも使えます。次の例では、htmlは「(String s) => '<html>${s}</html>'」という関数となり、bodyは「(String s) => '<body>${s}</body>'」という関数になります。htmlもbodyも変数tagの値をキャプチャして処理の中で利用しています。
Function f(String tag) { return (String s) => '<${tag}>${s}</${tag}>'; } main() { var html = f('html'); var body = f('body'); var s = html(body('Hello, Dart!')); print(s); }
実行結果は次のようになります。
<html><body>Hello, Dart!</body></html>
次ページでは、Dartでサーバアプリを作成してみましょう。DartではWebSocketが使えるので、これを使ったサーバを用意してみます。あまり凝ったことはせずに、渡されたデータをJSON形式にして返すだけの処理にしてみます。
クラスやメソッドの概念についての説明などは省略しますが、クラスベースのオブジェクト指向を使ったことがあれば大体感じが分かるはずです。
Copyright © ITmedia, Inc. All Rights Reserved.