Dartツアー(8)残り
Flutterを始めてみましたが、コードはDart言語で書きます。という訳で、Dart言語のツアーを見て勉強しながら、自分用にメモをまとめてみました。今回は残り全部です。
前回分は以下から。
ジェネレータ
一連の値をだらだらと生成する必要がある場合、ジェネレータ関数の使用を検討する。Dartは2種類のジェネレータ関数を内蔵している。
- 同期式ジェネレータ:Iterableオブジェクトを返す
- 非同期ジェネレータ:Streamオブジェクトを返す
同期ジェネレータ関数を実装するには、関数本体をsync*とマークし、yieldステートメントで値を送出する。
非同期ジェネレータ関数を実装するには、関数本体をasync*としてマークし、yieldステートメントを使用して値を送出する。
ジェネレータが再帰的な場合、yield*を使用することでパフォーマンスを向上させることができる。
なんらかのデータ列を生成する機能です。テストなんかに便利そうです。
呼び出し可能クラス
Dartクラスのインスタンスを関数のように呼び出せるようにするには、call()メソッドを実装する。
次の例では、WannabeFunction クラスが call() 関数を定義しており、3 つの文字列を受け取り、それぞれをスペースで区切って連結し他ものに感嘆符を追加する。
サンプルだけだと普通に関数書けば良いじゃん、となるのでメリットが不明瞭。ツアーというからには、もうちょっと「こういう使い方するんだ!」的なものを期待してしまいますが、ツアー全般であまりそういうのはなかったりします。
なお、callの使い方として、nullableなクラスでFoo?.call()みたいな書き方ができるという話を見かけました。イベントハンドラで多用するようです。
アイソレート
モバイルを含め、ほとんどのコンピュータはマルチコアのCPUを搭載している。これらのコアをすべて活用するために、開発者は従来、共有メモリのスレッドを同時に走らせる方法をとっていた。しかし、共有状態の同時実行はエラーが発生しやすく、複雑なコードになる可能性がある。
スレッドの代わりに、すべてのDartコードはアイソレート内部で実行される。各 Dart アイソレートは実行の単一スレッドを持ち、他のアイソレートと変更可能なオブジェクトを共有しない。
詳しくは以下の各項を参照。
- Dartにおける並行処理
- dart:isolate API リファレンス(Isolate.spawn()、TransferableTypedData を含む
- Flutter サイトのクックブック:バックグラウンド解析
- Isolateサンプルアプリ
いわゆるスレッドとか、並列処理のための仕組み。Go言語で言えばgoルーチン。スクリプト言語的に使う分にはあまり意識しませんが、アプリを作る際には意識が必要な部分になります。
型の別名(typedef)
型の別名(typedefというキーワードで宣言されるためtypedefと呼ばれることが多い)は、型を参照するための簡潔な方法である。以下は、IntList という名前の型エイリアスを宣言して使用する例である。パタメータを使うこともできる。
注:2.13以前は、型定義は関数型に限定されている。新しい型定義を使用するには、少なくとも2.13の言語バージョンが必要。
ほとんどの場合、関数には typedef の代わりにインライン関数型を使用することを勧める。しかし、関数の型定義はまだ役に立つことがある。
メタデータ
メタデータは、コードに関する追加情報を提供するために使用します。メタデータ注釈は@という文字で始まり、その後にコンパイル時の定数(deprecatedなど)への参照、または定数コンストラクタへの呼び出しが続きます。
すべての Dart コードで利用できるアノテーションは @Deprecated、@deprecated、@overrideの3種である。override の使用例については、「クラスの拡張」を参照すること。以下は、@Deprecated アノテーションを使用した例である。
class Television {
/// Use [turnOn] to turn the power on instead.
@Deprecated('Use turnOn instead')
void activate() {
turnOn();
}
/// Turns the TV's power on.
void turnOn() {...}
// ···
}
この記述だけでは何が何やらです。ツアーと言いつつ、なんかわかっている人向けの感じです。おそらく、Javaのアノテーションを知っていることが前提になっています。(自分のJava知識はそれ以前。大雑把なことしか理解していません。)
@deprecatedは昔の書き方で、今これを書くとコンパイラに@Deprecated('メッセージ’)に直せと言われます。ですので、実質的には@Deprecatedと@overrideの2種を使うべき、となります。
@Deprecatedは非推奨コメントを書くために使います。例えば、互換性のために残してあるけど将来的には廃止するので使わないでほしいとか、とりあえず実装優先で書いたけど後で直したいとか。
@overrideは継承でオーバーライドすることを示すために使います。なくても動作しますが、プログラマの意図を明確にするために、オーバーライドしている際に@overrideがないとコンパイラが注意喚起します。誤って同名の関数を定義してしまったわけではなく、意図してオーバーライドしていることを示すために使うものです。
どちらもJavaのアノテーションで同様な意味を持つものです。
独自のメタデータアノテーションを定義できる。ここでは、2つの引数を取る@Todoアノテーションを定義する例を示す。
メタデータはライブラリ、クラス、typedef、型パラメータ、コンストラクタ、ファクトリ、関数、フィールド、パラメータ、変数宣言の前、およびimportまたはexport指示文の前に表示することができる。リフレクションを使って実行時にメタデータを取得できる。
これも説明不足というか、Javaのアノテーションを知っている前提で書いてあるので、知らないと何が何やらです。
7行目までのクラス定義部分は、本来は別ファイルで宣言するライブラリとして使う想定です。何の説明もないですが、複数人で開発している場合に、誰かに何かしてほしい旨をソース中に記述するために使う想定かと思います。
上のサンプルの場合、9行目でsethさんにこの部分、いい感じにしといてと伝えるために使っています。これだけならコメントで書けば良いことですが、リフレクションという機能を使ってこの情報を収集できるので、何らかのツールを使ってTodoリストみたいなものをソースから出力できる、はずです。(個人的にはソース中での埋め込み指示はしたことないです。)
注釈(アノテーション)ですので、9行目が動作に影響を及ぼすことはありません。が、上に書いたようにリフレクションという機能を使うと動作に影響を及ぼすことができてしまいます。
コメント
Dartは、単一行コメント、複数行コメント、およびドキュメントコメントをサポートしている。
1行コメント
1行コメントは // で始まる。//と行末の間のすべては、Dart コンパイラによって無視される。
void main() {
// TODO: refactor into an AbstractLlamaGreetingFactory?
print('Welcome to my Llama farm!');
}
複数行コメント
複数行のコメントは /* で始まり、*/ で終わる。/*と*/の間はすべてDartコンパイラによって無視される(そのコメントがドキュメンテーション・コメントである場合を除く。) 複数行コメントは入れ子にすることができる。
void main() {
/*
* This is a lot of work. Consider raising chickens.
Llama larry = Llama();
larry.feed();
larry.exercise();
larry.clean();
*/
}
ドキュメンテーション・コメント
ドキュメンテーション・コメントは、///または/**で始まる複数行または1行のコメントである。連続した行で /// を使用すると、複数行のドキュメンテーション・コメントと同じ効果がある。
ドキュメンテーション・コメントの内部では、括弧で囲まれていない限りすべてのテキストが無視される。括弧を使用すると、クラス、メソッド、フィールド、トップレベル変数、関数、パラメータを参照することができる。括弧内の名前は、ドキュメント化されたプログラム要素の語彙的スコープで解決される。
以下は、他のクラスや引数を参照するドキュメント・コメントの例です。
/// A domesticated South American camelid (Lama glama).
///
/// Andean cultures have used llamas as meat and pack
/// animals since pre-Hispanic times.
///
/// Just like any other animal, llamas need to eat,
/// so don't forget to [feed] them some [Food].
class Llama {
String? name;
/// Feeds your llama [food].
///
/// The typical llama eats one bale of hay per week.
void feed(Food food) {
// ...
}
/// Exercises your llama with an [activity] for
/// [timeLimit] minutes.
void exercise(Activity activity, int timeLimit) {
// ...
}
}
クラスの生成されたドキュメントでは、[feed] が feed メソッドのドキュメントへのリンクになり、[Food] が Food クラスのドキュメントへのリンクになる。
Dart のコードを解析して HTML 文書を生成するには、Dart の文書生成ツールである dart doc を使用する。生成されたドキュメントの例については、Dart API ドキュメントを参照すること。コメントをどのように構成するかについてのアドバイスは、 Effective Dart :Documentationを参照すること。
サマリー
このページでは、Dart言語でよく使われる機能をまとめた。より多くの機能が実装される予定だが、既存のコードを壊すことはないと思われる。詳しくは、Dart言語仕様とEffective Dartを参照すること。
Dart のコアライブラリについては、「A Tour of the Dart Libraries」を参照すること。
最後に
以上でDart言語公式ドキュメントの「ツアー」部分を読み終わりました。この先にもさまざまな項目が並んでいます。全てを読みきれないので、とりあえずはここまでにします。
ディスカッション
コメント一覧
まだ、コメントがありません