CodeZine(コードジン)

特集ページ一覧

Dart言語の便利な拡張表現とパッケージ管理

Flutterで始めるモバイルアプリ開発 第7回

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2021/04/19 11:00

 これまでDart言語仕様について説明してきましたが、今回はそこで紹介できなかった「カスケード表記」や「コレクション作成の拡張表現」などのシュガーシンタックスや、パッケージの作成方法と利用方法やプロジェクトファイルについて紹介します。これまで紹介した内容に比べて小粒ではありますが、「カスケード表記」や「コレクション作成の拡張表現」などはコーディングする上で、便利な表記方法なのでぜひ覚えておくとよいです。

目次

はじめに

Flutter2のリリースについて

 2021年3月4日にFlutter2がリリースされました。Flutter2では、Android/iOSだけではなく、Windows/Mac/Linuxなどのデスクトップアプリに加え、Webアプリ版もリリースされました。Flutterに魅力を感じ、さまざまなプラットフォーム用にアプリケーションを作りたいと思う開発者にとっては、まさに今回のリリースはFlutterの今後の世界を広げるリリースの1つとなることでしょう。

 一方、AndroidやiOS用のスマホアプリ用と捉えている方にとっては、メジャーアップデートというよりは、マイナーアップデートに近い印象です。また、Web版は開発過程でエミュレータの代わりに使う場合に便利そうな印象を受けました。

 そして、今回紹介しているDartも2.12に更新されました。Dartの更新もマイナーアップデートなのですが、実はNull safetyという大きな変更があります。これは、関連するライブラリなども含めて全体的な変更が必要になります。そのため、実際に活用するのはもう少し先になりそうです。

 Flutter2のコマンドを使ってプロジェクトを作成してもDart2.12以前のバージョンがデフォルトになっていたので、利用する人は意識的に有効にする機能という位置付けになります。

対象読者

 Dart言語について特に知っている必要はありませんが、他の言語の基本を知っている方を対象に説明いたします。特に、JavaScriptやTypeScriptもしくは、Javaなど言語を使ってプログラミングしたことがある方であれば、より理解がしやすくなります。

カスケード表記

 同じオブジェクトのメソッドを連続して実行する場合には「..」を使った便利な表記方法があります。「..」演算子を利用することで、メソッドチェーンと同じような記述が可能になります。

[リスト1]カスケード表記を使わない場合と使った場合の表記例(cascade.dartの抜粋)
// (1)使わない場合
var b1 = Builder();
b1.text = "sample";
b1.opts = Opts();
b1.opts.type = "normal";
b1.create();

// (2)カスケード表記を使った場合
var b2 = Builder()
  ..text = "sample"
  ..opts = (
    Opts()
      ..type = "normal"
  )
  ..create();

 (1)は、カスケード表記を使わない場合の例です。このコードを、カスケード表記を使って記述すると(2)のようになります。カスケード表記とインデントとを併用するとわかりやすいコードが記述できます。

コレクション作成を拡張する表現

 Dartでは、コレクションを定義する際に非常に便利な表現機能があります。

spreads表現

 spreads表現とは、コレクションの前に「...」を置くことで中身を展開できるしくみのこと。既存のコレクションデータを利用して、新たにコレクションデータを作る場合に便利な機能です。リスト2は、既存のListデータを利用して新たにListデータを作成する場合の例です。

[リスト2] spreads表現を使ったコード例(collection_spreads.dartの抜粋)
// (1) 通常のListデータの定義
List<Widget> androidWidgets1 = [
  Widget("android1"),
  Widget("android2"),
];
List<Widget> children1 = [
  Widget("sample1"),
  ...androidWidgets1, // (2) ...を使った表現
  Widget("sample2")
];
// 実行結果
print(children1);
// [sample1, android1, android2, sample2]

 (1)は挿入するためのListデータです。そして、(2)のように、...を使うと(1)で生成したListデータを展開したものをその場に挿入できます。List以外にもMapなどでも同様の表現ができます。

Collection if表現

 さらに、コレクション要素を追加する際に、条件分岐や繰り返しの処理を加えることも可能です。リスト3は、コレクション定義内に条件分岐(collection if)を使う例です。

[リスト3] collection ifを使ったコード例(collection_if.dartの抜粋)
var isAndroid = false;
var isIos = true;

var appends = [Widget("append1"),Widget("append2")];

List<Widget> children = [
Widget("sample1"),
// (1) ifを記述
if(isAndroid)
  AndroidWidget("sample2")
// elseでさらに条件を追加
else if(isIos)
  IOSWidget("ios1")
//  (2)複数を追加したい場合にはspreads表現を組み合わせる
else
  ...appends,
Widget("sample3")
];
print(children);
// [sample1, ios1, sample3]

// 参考 : isAndroid = true, isIos = false の場合の結果
// [sample1, sample2, sample3]

// 参考 : isAndroid = false , isIos= false の場合の結果
// [sample1, append1, append2, sample3]

 (1)のように、if...else if...elseがリスト定義の中で利用できます。ただし、通常のif文と異なり、{}の配下に複数のコードを記述することはできません({}を記述した場合には、Map型と見なされます)。複数の子要素を追加したい場合には、先ほど紹介したspreads表現を利用してください。

Collection for表現

 同じく、コレクション内で繰り返し処理を加えることもできます。リスト4は、その例です。

[リスト4] collection for表現の利用例(collection_for.dartの抜粋)
var appends = ["append1","append2"];
var children = [
  Widget("sample1"),
  Widget("sample2"),
  for(var name in appends) Widget(name), // (1)
  Widget("sample3")
];
print(children);
// [sample1, sample2, append1, append2, sample3]

 (1)のようにコレクション定義内にforを利用することができます。先ほどのspreads表現、collection ifとcollection forを組み合わせることで、非常に強力な表現ができるようになります。

nullを考慮したコード

 Dartは、nullの可能性がある変数を言語レベルで安全に扱うことができます。

 特に、バージョン2.12(Flutter2と共にリリース)からはより安全なnullに対策ができるコードが記述できます。この2.12からの変更点は非常に大きいため、現在のコードを記述する上でも知っておいた方がよい内容です。すぐに対応が必要というわけではありませんが、その内容についても簡単に触れたいと思います。

Dart 2.11まで(Flutter1)でのnullを考慮したコード

 現行バージョンでは、nullの可能性がある変数にアクセスする際に、「?.」を利用するとnullの場合にはその後の変数にアクセスすることを抑制することができます。そのため、リスト5のようにそれぞれの変数でnullチェックをしなくてもエラーにならないコードを記述できます。

[リスト5] null値のクラス変数へのアクセス例(null.dartの抜粋)
// (省略)
main(){
  var root = Node.root();
  root.appendChild("child1");
  // どのインスタンがnullでもエラーにならない記述
  var target1 = root?.firstChild?.next?.firstChild; // (1)
  // (省略)
}

 (1)のようにインスタンス変数にアクセスする際に「.」の代わりに「?.」を利用します。このサンプルコードでは、nextという変数がnullになるのですが、「?.」が指定されているために、その後のfirstChildは評価されません。またこの式の値はnullになります。

 ただし、本来はnullになってはいけいない場所で使用してしまうとエラーが発生しないためにより問題が分かりにくくなるケースもあるのでご注意ください。

Dart 2.12以降(Flutter2)でのnullへの考慮

 先ほどの例は、変数の値にnullが入っている場合でも、nullチェックせずに安心して変数を利用するためのコードでした。一方、2.12以降では変数の定義自体にnullを許可、または、許可しないという管理ができるようになります。

 ただし、2.12以前で利用してきた表記方法の意味が変わってしまうため、非常に大きな変更です。今すぐに移行が必要になることはありませんが、将来的には影響が出てくることが予想されるので、新規にコードを記述する際には変更を意識して準備しておく必要があるでしょう。

 リスト6は、バージョン2.12以降を考慮した場合のコード例です。

[リスト6] nullを考慮した変数・関数・クラス変数の定義例(null_safety.dartの抜粋)
int? num = null; // (1)
int  num2 = 2;   // (2)

int? randValue(){  // (3)
  return null;
}
class Node{
  late int size; // (4)
  Node(){
    size = 0;
  }
}

 (1)はnullを許容する変数の定義例です。型指定の後に「?」を指定することで、この変数にはnullが設定される可能性があることを示します。現行バージョンでの「?」を指定しない場合と同様です。

 (2)はこれまでの記述と同様ですが、こちらはnullの値が設定できない変数の定義方法です。このようにnullを許容する変数は明示する必要が生じ、これまでと意味が異なります。また、(3)のように関数の結果にnullがあり得る場合には、同様に「?」を指定します。「?」の指定は引数などでも同様のルールになります。

 インスタンス変数を定義する場合も同様です。しかし、nullを許容しない変数でも定義時には値を指定できず、コンストラクタで指定する場合があります。その場合には、(4)のようにlateキーワードを使ってそのことを明示します。このように大きな違いが生じていることがわかります。ここではすべてを紹介してできませんが、詳しく知りたい方はこちらを参照してください。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

あなたにオススメ

著者プロフィール

  • WINGSプロジェクト 小林 昌弘(コバヤシ マサヒロ)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。個人紹介主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしど...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XM...

バックナンバー

連載:Flutterで始めるモバイルアプリ開発
All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5