本記事は、マルチプラットフォーム開発のSDK【Flutter】を用いたモバイルアプリ開発入門の為の記事です。
Flutterアプリケーションを開発する際に使われるプログラミング言語はDart言語です。Flutterが注目されるまでほぼ知られていなかったこの言語。どんな特徴があるのか、歴史も含めてまとめていきます!
Dartが作られた目的
Dartは、2011年にGoogleによって開発・公開されたWebアプリケーション開発のためのプログラミング言語です。
Javascriptの欠点を補う目的として作られました。
現在では、クライアントサイド、サーバーサイドだけでなく、モバイル領域(Flutter)にも使われています。
Dartの歴史
公開後、DartはGoogleが開発しているChromeブラウザに組み込まれる(Dart仮想マシンを組み込む)予定でした。
しかし2015年、Googleはこれを断念しその他のaltJS(Typescript)などのように、JavaScriptへのコンパイルに専念すると発表しました。
これ以降Dartは
- Microsoft社が開発した「TypeScript」がGoogleの社内標準言語になったと2017年4月に発表があった
- 2018年最も学ぶ価値のないプログラミング言語の1位になった
など、2018年まで人気が低い状態が続いていました。
しかし、2018年の12月にGoogleがモバイル開発SDK【Flutter】の製品版リリースを発表されて以降、急速に世界中の開発者の注目を集めてきました。
2019年の最も学ぶ価値のないプログラミング言語では、14位に下がり、注目されていることが分かります。(以下ランキング記事のリンクです。)
Dartの特徴
ここからは、Dartの特徴について、少し詳細に踏み入れて解説をしていきたいと思います。
➀高パフォーマンス
Dartは、パフォーマンスが高く、大規模開発にも対応可能です。
➁オブジェクト指向型言語
Dartは、Javaなどと同様のクラスベースのオブジェクト指向型言語です。
全ての型の元がオブジェクト(nullもオブジェクト)であるという特徴を持ちます。
➂静的型付けにも対応
Dartは、静的型付けにも対応しています。
しかし、これも任意です。全ての型を許容したい場合、dynamicキーワードを用いることもできます。
すなわち、Javascriptのように動的型付け言語として扱うことも可能です。
言語仕様
特徴的な言語仕様についても簡単に解説していきます。
DartPadでDartを試すことができます。
A tour of the Dart Languageでは、Dartについてより詳細に解説されています。
keyword
Javaのようにprivate、public、protectedはありません。そのかわり、名前の前に_
を付けることで同ライブラリ外からのアクセスを制限することができます。(privateを実現)
また、@protectedを宣言することでprotectedを実現します。
ビルトイン型
- int, double
- String
- Boolean
- List
- Set
- Map
➀int, double
intは64bitの整数型です。-2 ^ 53 ~ 2 ^53 までが利用可能です。
doubleは64bitの浮動小数点型です。
void main() {
int hoge = 100;
double fuga = 1.1;
print("hoge: $hoge");
print("fuga: $fuga");
}
➁String
StringはUTF-16単位の配列です。文字列を作成する際に使います。
void main() {
String hoge = "hoge";
print("hoge: $hoge");
}
➂Boolean
Javascriptなどと異なり、Dartでtrueと解釈されるのはtrueのみです。それ以外はfalseと解釈されます。
void main() {
bool hoge = true;
print("hoge: $hoge");
// // Dartではtrueのみtrueと扱われるため、これはコンパイルエラー
// if (1) {
// print("ok");
// }
}
➃List
配列はDartではListと呼ばれます。
Generic型(Listの後に<設定したい型>を記述)を使うと、そのListで扱える型を制限できるため、型安全を保つことができます。
void main() {
List sampleList = [1, 2, 3, "1234"];
print(sampleList);
// 型がintのみ設定されているのに、Stringが入力されているため、エラー
// List<int> sampleIntList = ["ss", 2];
}
➄Set
一意性を保った配列を作りたい場合、Setを使います。
void main() {
// 最後のfugaは無視される
Set<String> sampleSet = {"hoge", "fuga", "fuga"};
var map = {};
// Setを明示していない場合、mapとして扱われるためエラー
//map.add("map");
print(map);
print(sampleSet);
}
➅Map
連想配列を作りたい場合、Mapを使います。
void main() {
// どちらも同じく、Keyがint型、ValueがString型として認識される
Map sampleMap = {1: "hoge", 2: "fuga", 3:"piko"};
Map<int, String> sampleMap2 = {1: "hoge", 2: "fuga", 3:"piko"};
print(sampleMap);
print(sampleMap2);
}
カスケード記号
..
でつなげることで、連続してオブジェクトの変数にアクセスすることができる。
querySelector('#confirm') // Get an object.
..text = 'Confirm' // Use its members.
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
// これは以下と同じ
var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
クラス
無名コンストラクター
Dartのコンストラクターの渡し方は他のプログラミング言語と大きくは変わりません。
以下のように書くことで、記述量を減らすことができます。
class Animal {
String name;
int power;
// 以下は同じ実行結果になる(厳密には異なります。)
// 冗長な書き方
// Animal(name, power) {
// this.name = name;
// this.power = power;
// }
// 簡潔な書き方
Animal(this.name, this.power);
}
名前付きコンストラクター
無名コンストラクターに加え、名前付きコンストラクターを作ることもできます。
class Animal {
String name;
int power;
Animal(this.name, this.power);
Animal.sample() {
name = "animal";
power = 100;
}
}
:
を使うことで、親クラスのコンストラクターを呼べる
サブクラスのコンストラクター内で親クラスのコンストラクターを呼ぶ場合、:
を使う必要があります。
class Animal {
String name;
int power;
Animal(this.name, this.power);
}
class Tiger extends Animal {
int height;
Tiger(this.height, String name, int power) : super(name, power);
}
:
を使うことで、変数の事前割り当てができる
引数の後に:
で繋げることで、変数を予め割り当てておくことができます。
Point.fromJson(Map<String, num> json)
: x = json['x'],
y = json['y'] {
print('In Point.fromJson(): ($x, $y)');
}
:
を使うことで、同一クラスの別コンストラクターも呼べる
同一クラス内で別のコンストラクターを呼び出したい場合、:
とthis
を使って呼び出すことができます。
class Point {
num x, y;
// The main constructor for this class.
Point(this.x, this.y);
// Delegates to the main constructor.
Point.alongXAxis(num x) : this(x, 0);
}
非同期関数
Dartは非同期処理をStreamとFutureで実現しています。
Future
Futureは、JavascriptでいうPromiseです。
.then
で繋げて非同期で値を取得します。
またエラー処理は.catchError
で実装できます。
Future<int> future = Future(foo);
future.then(
(int value) => bar(value)
).catchError(
(e) => 499
);
また、Promiseは、async, awaitを用いることで同期処理のように記述することもできます。
これもJavascriptと似ていますね。
Future checkVersion() async {
try {
var version = await lookUpVersion();
} catch(error) {
// エラー処理
} finally {
// 初期化処理
}
}
Stream
Streamは連続したデータを非同期で受け取る機能を実装します。
Streamを受け取る関数はasyncを記述されていなければなりません。また、非同期のfor文であるawait for
を用いて返された値を受け取ることが可能です。
Future<int> sumStream(Stream<int> stream) async {
var sum = 0;
await for (var value in stream) {
sum += value;
}
return sum;
}
Streamについては、以下のリンクで詳しく解説されています。
まとめ
Dartプログラミング言語について、歴史から言語仕様まで簡単に解説しました。
Dartは独特の文法などはそこまで多くありません。JavascriptやJavaを使ったことのある方でしたらすぐに慣れる言語ですね。
ただし、モダンな仕様(FutureやStreamなど)も一通り採用しており、今後も利用価値が高い言語であると言えます。
また、Flutterの適用範囲をモバイル領域だけでなく、他の領域に拡げようとしている試みもあります。
- Web領域ではHummingBird
- デスクトップ領域ではflutter-desktop-embedding
- googleの新OS「Fucsha」にFlutterを標準実装
上記はまだまだ構想段階ではありますが、高い研究開発力のあるGoogleならこれをやってのけてくれるでしょう。
この記事が少しでもお役に立てたら嬉しいです。
Flutter、Dartでのアプリ開発の楽しさを是非一緒に体験していきましょう!