Dart
Dart(ダート)は、Googleが開発したスクリプト言語で、元々はJavaScriptを置き換えることを目的にしていました。 Googleは2011年までにChromeでDartVMをサポートすることを計画していましたが[1]、2015年にChromeへのDartVM統合を中止しました[2]。 その後、TypeScriptがGoogle社内の標準スクリプト言語として承認され、Dartは重要な言語であるものの、競合する言語となりました[3]。
このように、ウェブブラウザ上のJavaScriptを置き換えることは失敗に終わったと見なされることがありましたが、2017年5月にGoogleが開発したオープンソースのUIの SDKであるFlutterが登場したことで、Dartの状況は一変しました。 Flutterは、Android、iOS、Linux、macOS、Windows、Google Fuchsia[4]やウェブ向けのクロスプラットフォームアプリケーションを単一のコードベースから開発するために使用されるSDKです。 DartはFlutterのアプリケーション記述言語として採用され、Flutterと不可分の存在となりました。現在、DartはFlutterアプリケーションの記述に必要不可欠であり、言語仕様はFlutterアプリケーションのニーズに合わせて改定されています。
インストールしないで実行する方法[編集]
DartPad というサイトを使うと、自分の環境にインストールしないでもブラウザ上で Dart のプログラミングが行なえます。
インストール方法[編集]
Get the Dart SDK を入手できます。
Windowsの場合は、公式インストール方法ではパッケージマネージャーの Chocolatey を使うのですが日本では馴染みがないようなので、これとは別にコミュニティによる用意されたインストーラを使うと良いでしょう。⇒ https://gekorm.com/dart-windows/
動作確認[編集]
dartのバージョンは、
dart --version
で確認できます。
PS C:\Users\user1> dart --version Dart SDK version: 2.15.0-168.0.dev (dev) (Thu Sep 30 12:23:13 2021 -0700) on "windows_x64"
のようにバージョン番号が出たら、成功です。
Hello World など[編集]
- コード例
main() { print("Hello world"); }
print関数などのよく使われる関数はdart:core
ライブラリにありますが、dart:core
ライブラリはimport不要で使えます。
実行方法は、コマンドプロンプトあるいはWindows Terminalで、
dart ファイル名.dart
です。
変数[編集]
Dartには整数型や浮動小数型などの型があります。変数の宣言のときに型を明示する方法と、初期化する値から型を推論する方法があります。
型を明示する方法[編集]
main() { int a = 3; int b = 2 * a; print(b); }
- 実行結果
6
初期化する値から型を推論する方法[編集]
Dartでは、型は var 宣言を使うことで型推論させることができます。
main() { var a = 4; var b = 1.23; print(a + b); }
- 実行結果
5.23
定数を宣言する場合[編集]
main() { final List<int> a = [1, 2, 3]; const List<int> b = [2, 3, 5]; print(a + b); a[1] = 9; print(a + b); // b[0] = 0; ← final で宣言すると指し示す先のオブジェクトの値も変更できないので、この文はエラー }
- 実行結果
[1, 2, 3, 2, 3, 5] [1, 9, 3, 2, 3, 5]
- finalで宣言すると、初期化以降値を変更できない変数をつくれます。
- finalで宣言された変数の指し示す先の値は変更できます。
- constで宣言すると、初期化以降値を変更できない変数をつくれます。
- constで宣言された変数は指し示す先の値も変更できません。
文字列への式の埋込み[編集]
文字列の中に、式を埋め込むことができます。
- コード例
main() { var num = 4; print("num + 3 is ${num + 3}\n"); }
- 実行結果
num + 3 is 7
文字列の中に ${ 式 }
の形式で埋込むと、実行時に展開されます。
文字列への変数の埋込み[編集]
文字列の中に埋込む式が単一の変数ならばより簡略化した形式で表現できます。
- コード例
main() { var num = 4; print("num is $num\n"); }
- 実行結果
num is 4
文字列の中に $変数名
の形式で埋込むと、実行時に展開されます。
バックスラッシュ・エスケープ・シーケンス[編集]
改行などに対するバックスラッシュ・エスケープ・シーケンスは他のプログラミング言語と同様に使えます。
「\」そのものを表示したい場合は、先頭にもうひとつ「\」をつけて「\\」のようにするだけです。
- コード例
main() { print("\\n"); }
- 実行結果
\n
コメント[編集]
コメントをソースコードに書くときは、//
や、/*
と*/
を使用します。
1行で終わるコメント[編集]
下記コードのように//
を使うと行末までがコメントになります。
- コード例
main() { var cat = "Miku"; // 猫の名前 print("The name of the cat is ${cat} \n"); }
- 実行結果
The name of the cat is Miku
複数行に渡るコメント[編集]
下記コードのように/*
と*/
で文を囲むと2行以上をコメントにできます。
- コード例
main() { /* 動物の種類 猫 犬 兎 */ var animals = ["cat", "dog", "rabbit"]; print(animals); }
- 実行結果
[cat, dog, rabbit]
関数[編集]
関数の定義と呼出し[編集]
関数は戻値の型と関数名と仮引数リストで定義します。 関数の呼出しは、関数名と実引数リストを与えます。
- コード例
main() { int add(int x, int y) { int z = x + y; return z; } // add関数に引数として1と2を指定する。 print(add(1, 2)); }
- 実行結果
3
ライブラリー[編集]
Dartには、様々な用途に特化した多くのライブラリーが存在します。以下は、Dartでよく使用されるライブラリーの一部です。
dart:async
- Dartの非同期処理を扱うためのライブラリーdart:math
- 数学関数を提供するライブラリーdart:io
- ファイル入出力やネットワーク通信を扱うためのライブラリーdart:convert
- JSONやUTF-8などのエンコーディングやデコーディングを扱うためのライブラリーdart:html
- Webアプリケーションを開発するためのHTML要素を提供するライブラリーhttp
- HTTP通信を扱うためのライブラリーflutter
- モバイルアプリケーションを開発するためのフレームワークであり、UIやネットワーク通信などの機能を提供するライブラリー
これらのライブラリー以外にも、様々な目的に特化したライブラリーが存在しています。Dartの公式ドキュメントや、Dart Pubと呼ばれるパッケージマネージャーで検索することで、必要なライブラリーを見つけることができます。
print関数などのよく使われる関数はdart:core
ライブラリーにあり、dart:core
ライブラリーはimportが不要ですが、それ以外のライブラリーはimportが必要です。
math ライブラリー[編集]
- コード例
import 'dart:math'; num numval = pi; main() { print(sin(pi / 4)); }
- 実行結果
0.7071067811865475
- ライブラリーのimport
import 'dart:math';
- num型
num numval = pi;
- num型は、数値ならば整数型でも浮動小数点数型でも保持できる変数を宣言します。
- ライブラリー関数の使用
print(sin(pi / 4));
Dartの型システムの説明の前なので、簡単な例の説明に留めました。
制御構造[編集]
Dartには、if-else文、for文、while文、do-while文、switch文、forEachメソッドなど、多様な制御構造があります。
- Dartプログラミング言語の主要な制御構造のチートシート
void main() { // if文 int x = 10; if (x > 5) { print("x is greater than 5"); } else if (x == 5) { print("x is equal to 5"); } else { print("x is less than 5"); } // forループ for (int i = 0; i < 5; i++) { print("i is $i"); } // for-inループ List<int> numbers = [1, 2, 3, 4, 5]; for (int number in numbers) { print("number is $number"); } // whileループ int count = 0; while (count < 5) { print("count is $count"); count++; } // do-whileループ int i = 0; do { print("i is $i"); i++; } while (i < 5); // switch文 String color = "red"; switch (color) { case "red": print("color is red"); break; case "green": print("color is green"); break; case "blue": print("color is blue"); break; default: print("color is not recognized"); break; } // break文 for (int i = 0; i < 5; i++) { if (i == 3) { break; } print("i is $i"); } // continue文 for (int i = 0; i < 5; i++) { if (i == 3) { continue; } print("i is $i"); } }
- 実行結果
x is greater than 5 i is 0 i is 1 i is 2 i is 3 i is 4 number is 1 number is 2 number is 3 number is 4 number is 5 count is 0 count is 1 count is 2 count is 3 count is 4 i is 0 i is 1 i is 2 i is 3 i is 4 color is red i is 0 i is 1 i is 2 i is 4 i is 5 i is 0 i is 1 i is 2 i is 4 i is 5
for文とif文の組合わせ[編集]
- for文とif文の組合わせ
main() { for (int i = 0; i < 10; i++) { if (i % 2 == 0) { print("$i は2の倍数です。"); } else if (i % 3 == 0) { print("$i は3の倍数です。"); } else { print("$i は2の倍数でも3の倍数でもありません。"); } } }
- 実行結果
0 は2の倍数です。 1 は2の倍数でも3の倍数でもありません。 2 は2の倍数です。 3 は3の倍数です。 4 は2の倍数です。 5 は2の倍数でも3の倍数でもありません。 6 は2の倍数です。 7 は2の倍数でも3の倍数でもありません。 8 は2の倍数です。 9 は3の倍数です。
- for文
for (int i = 0; i < 10; i++) {
- C言語などと共通する三文式for文です。
- 最初の文は初期設定で変数の宣言もでき、宣言された変数のスコープはfor文が終わるまでです。
- 二番目の文は反復条件で、値はtrueかfalseである必要があり、trueであるかぎる続く文(内容としましょう)を反復します。
- 三番目の文は内容を実行したあと毎回評価されます。
- if文
if (i % 2 == 0) { print("$i は2の倍数です。"); } else if (i % 3 == 0) { print("$i は3の倍数です。"); } else { print("$i は2の倍数でも3の倍数でもありません。"); }
i % 2
は、「iを2で割った余り」を表す式で、条件式全体i % 2 == 0
は、「iを2で割った余りが0ならtrueそうでなければfalse」を表す式、、となります。- if文は条件式がtrueであればifに続く文を、(else節があれば)条件式がfalseならばelseに続く文を実行します。
- if の条件式に一致せずelseがある場合はelseに続く文を実行しますが、if文も文なので
} else if (i % 3 == 0) {
のように続けて別の条件を評価することができます[5]。
while文とif文の組合わせ[編集]
- while文とif文の組合わせ
main() { int i = 0; while (i < 10) { if (i % 2 != 0) { print("$i は奇数です。"); } else { print("$i は偶数です。"); } i++; } print(i); }
- 実行結果
0 は偶数です。 1 は奇数です。 2 は偶数です。 3 は奇数です。 4 は偶数です。 5 は奇数です。 6 は偶数です。 7 は奇数です。 8 は偶数です。 9 は奇数です。 10
- while文とスコープ
print(i);
- 上のfor文とif文の組合わせをwhileを使ってあらわあすと、概ねこのようになります。
- 「概ね」と言うのは、変数iのスコープは(while文の外で宣言しているので)main関数末まで続くので、while文を抜けても
print(i);
は有効です。
for文とswitch文の組合わせ[編集]
- for文とswitch文の組合わせ
main() { for (int i = 1; i < 10; i++) { switch (i) { case 2: case 4: case 6: case 8: print("$iは、2の倍数です。"); break; case 3: case 6: case 9: print("$iは、3の倍数です。"); break; case 5: print("$iは、5の倍数です。"); break; case 7: print("$iは、7の倍数です。"); break; default: print("$iは、2,3,5,7のいづれの倍数でもありません。"); } } }
- 実行結果
1は、2,3,5,7のいづれの倍数でもありません。 2は、2の倍数です。 3は、3の倍数です。 4は、2の倍数です。 5は、5の倍数です。 6は、2の倍数です。 7は、7の倍数です。 8は、2の倍数です。 9は、3の倍数です。
forEachメソッド[編集]
forEach
メソッドは、リストやマップなどのコレクションの各要素に対して指定した処理を実行するためのメソッドです。
- forEachメソッド
void main() { List<String> fruits = ["apple", "banana", "orange"]; // リストの各要素に対して、処理を実行する fruits.forEach((fruit) { print(fruit); }); }
- 上記の例では、
List
型のfruits
という変数に対してforEach
メソッドを呼び出し、fruits
の各要素に対して、引数で指定された無名関数を実行しています。無名関数内では、print
メソッドを使用して、各要素をコンソールに出力しています。
また、forEach
メソッドは、以下のようにラムダ式を使用して簡略化することもできます。
- forEachメソッドとラムダ式の組み合わせ
void main() { List<String> fruits = ["apple", "banana", "orange"]; // リストの各要素に対して、処理を実行する(ラムダ式) fruits.forEach((fruit) => print(fruit)); }
- 上記の例では、引数で指定する無名関数をラムダ式で表しています。これにより、コードの記述量が簡略化されます。
for文とコレクションの組合わせ[編集]
- for文とコレクションの組合わせ
main() { const array = [2, 3, 5, 7]; print(array.runtimeType); for (var x in array) { print("for-in: $x"); } array.forEach((item) { print("forEach: $item"); }); const set = {2, 3, 5, 7}; print(set.runtimeType); for (var x in set) { print("for-in: $x"); } set.forEach((item) { print("forEach: $item"); }); const map = {'apple': 'リンゴ', 'orange': 'オレンジ', 'banana': 'バナナ'}; print(map.runtimeType); for (var key in map.keys) { print('$key : ${map[key]}'); } for (var value in map.values) { print('for in map.values: $value'); } map.forEach((var key, var value) { print('forEach: $key : $value'); }); }
- 実行結果
JSArray<int> for-in: 2 for-in: 3 for-in: 5 for-in: 7 forEach: 2 forEach: 3 forEach: 5 forEach: 7 _UnmodifiableSet<int> for-in: 2 for-in: 3 for-in: 5 for-in: 7 forEach: 2 forEach: 3 forEach: 5 forEach: 7 ConstantStringMap<String, String> apple : リンゴ orange : オレンジ banana : バナナ for in map.values: リンゴ for in map.values: オレンジ for in map.values: バナナ forEach: apple : リンゴ forEach: orange : オレンジ forEach: banana : バナナ
オブジェクト指向プログラミング[編集]
Dartはオブジェクト指向言語であり、クラスを使ってオブジェクトを定義できます。クラスはフィールドとメソッドを持ち、フィールドはオブジェクトの状態を表し、メソッドはオブジェクトの振る舞いを定義します。
以下は、Dartでクラスを定義し、オブジェクトを作成する例です。例として、Personクラスを定義し、名前と年齢をフィールドに持ち、年齢を1歳増やすメソッドを定義します。また、main関数で2つのPersonオブジェクトを作成し、1つのオブジェクトの年齢を増やして表示します。
- クラスの例
// Personクラスの定義 class Person { String name; // 名前 int age; // 年齢 // コンストラクタ Person(this.name, this.age); // 年齢を1歳増やすメソッド void incrementAge() { age++; } } void main() { // Personオブジェクトの作成 var person1 = Person('Alice', 20); var person2 = Person('Bob', 25); // person1の年齢を1歳増やす person1.incrementAge(); // person1とperson2の情報を表示する print('Person 1: ${person1.name}(${person1.age})'); print('Person 2: ${person2.name}(${person2.age})'); }
- 実行結果
Person 1: Alice(21) Person 2: Bob(25)
- まず、Personクラスが定義されています。このクラスには、名前と年齢を表すString型の
name
フィールドとint型のage
フィールドが含まれています。また、このクラスには、名前と年齢を引数として受け取るコンストラクタと、年齢を1歳増やすメソッドincrementAge
が含まれています。 - 次に、
main
関数では、2つのPersonオブジェクトを作成し、1つのオブジェクトの年齢を増やしています。var
キーワードを使って、Personオブジェクトを作成しています。Person('Alice', 20)
は、Person
クラスのコンストラクタを呼び出し、name
を'Alice'、age
を20で初期化しています。 - その後、
person1
オブジェクトのincrementAge()
メソッドが呼び出され、その結果、person1
オブジェクトのage
フィールドが1増えます。 - 最後に、
person1
とperson2
の情報を表示するために、print()
関数が使用されます。それぞれのオブジェクトの名前と年齢が表示されます。
継承[編集]
継承は、既存のクラスを基にして新しいクラスを定義することができます。
- 継承の例
// Personクラスの定義 class Person { String name; // 名前 int age; // 年齢 // コンストラクタ Person(this.name, this.age); // 年齢を1歳増やすメソッド void incrementAge() { age++; } } void main() { // Personオブジェクトの作成 var person1 = Person('Alice', 20); var person2 = Person('Bob', 25); // person1の年齢を1歳増やす person1.incrementAge(); // person1とperson2の情報を表示する print('Person 1: ${person1.name}(${person1.age})'); print('Person 2: ${person2.name}(${person2.age})'); }
- 実行結果
Tama is eating. Meow!
- この例では、
Animal
という親クラスが定義され、name
というインスタンス変数とeat()
というメソッドが定義されています。そして、Cat
という子クラスがAnimal
を継承しています。Cat
はname
を引数に取るコンストラクタとmeow()
というメソッドを持っています。 main
関数では、Cat
のインスタンスであるcat
を作成し、eat()
とmeow()
メソッドを呼び出しています。eat()
メソッドはAnimal
クラスから継承されたもので、meow()
メソッドはCat
クラスで定義されたものです。
脚註[編集]
- ^ Google Operating System: Dash, Google's Alternative to JavaScript
- ^ “ChromeへのDartVM統合を断念、Dart開発チームが発表。今後はJavaScriptへのコンパイルにフォーカス”. Publickey (2015年3月26日). 2017年4月15日閲覧。
- ^ “TypeScriptが標準言語になっても、Dartのことは忘れてませんよとGoogle担当者がフォロー”. Publickey (2017年4月12日). 2017年4月15日閲覧。
- ^ “Google's "Fuchsia" smartphone OS dumps Linux, has a wild new UI”. Ars Technica.テンプレート:Cite web/error
- ^ 他の言語では、elseifやelsifなどの特別な表現を用意している場合がありますが、Dartは「else節に対応する文がif文」と表現します。