Dartのディレクティブたち

9 min read読了の目安(約8300字

ディレクティブという単語がそれらのみを指しているのかわかりませんが、importexportなどのライブラリの読み込みに関する単語のまとめです。

普段importasぐらいしか使わないけど、そういえばいろいろあったよなーと思い、まとめ始めたらなんか知らないのまで出てきました。


ディレクティブたち

  1. library

    • ライブラリに名前をつけるために使用します。
    • 後述のimportを用いて読み込むことのできるものはすべてライブラリです。
    • libraryと明示しなくても、Dartで書かれたアプリケーションは自動的にタグがつけられて一つのライブラリとして扱われます。[1]
    • ライブラリレベルでドキュメントを書かないのであればlibraryは省略することが推奨されています。[2]

      Note: When the library directive isn’t specified, a unique tag is generated for each library based on its path and filename. Therefore, we suggest that you omit the library directive from your code unless you plan to generate library-level documentation.

    library my_library; // 省略可
    
  2. import

    • ライブラリを読み込むために使用します。
    • 同じパッケージ内のライブラリ(自身がいるlib内にある別のライブラリ)を読み込む時はpackage:で始まる明示的なパスで指定せず、相対パスを使用する。[3]
    lib/my_library.dart
    import 'package:my_package/src/other_library.dart'; // Bad
    
    import 'src/other_library.dart'; // Good
    
  3. export

    • 外部に公開するライブラリを指定するために使用します。メインのライブラリにexportを記述することで、メインのライブラリを読み込むだけでexportで指定されたライブラリにもアクセスできます。
    lib/my_library.dart
    export 'src/foo.dart';
    export 'src/bar.dart';
    
    someones_library.dart
    import 'package:my_library/my_library.dart';
    
    void main() {
      foo(); // foo.dart内にある関数
      bar(); // bar.dart内にある関数
    }
    
  4. part

    • 後述のpart ofとセットで使用されます。
    • 一つのライブラリを複数のファイルに分割するために使用します。
    • 公式からはpartpart ofでのファイル分割よりも、個別のライブラリとして分割してimportでアクセスすることが推奨されています。[4]

      Note: You may have heard of the part directive, which allows you to split a library into multiple Dart files. We recommend that you avoid using part and create mini libraries instead.

    my_library.dart
    library my_library;
    
    part 'src/part_a.dart';
    part 'src/part_b.dart';
    
  5. part of

    • 先述のpartとセットで使用されます。
    • 一つのライブラリを複数のファイルに分割するために使用します。
    • part ofディレクティブはDartの歴史的理由でそれ自身が属している(part ofである)ライブラリの名前を使用できるようですが、他のディレクティブと同様にそのライブラリへのパスを文字列で指定することが推奨されています。[5]
    part of my_library; // Bad
    
    part of '../../my_library.dart'; // Good
    
    part_a.dart
    part of '../../my_library.dart';
    
    part_b.dart
    part of '../../my_library.dart';
    

オプション的なものたち

  1. show

    • 指定したクラスや関数のみを参照します。
    import 'package:other_package/other_package.dart' show SomeClass;
    
  2. hide

    • 指定したクラスや関数を参照しないようにします。
    import 'package:other_package/other_package.dart' hide SomeClass;
    
  3. as

    • 読み込むパッケージに名前をつけて呼び出す際のプレフィックスとし、クラス名や関数名の競合を避けます。
    import 'package:other_package/other_package.dart' as otherPackage ;
    

    たとえば
    これまでFirebase Authenticationのプラグインでは認証ユーザーをFirebaseUserとしていましたが、最近のアップデートでUserに変更されました。認証機能を使うようなアプリであればUserクラスは自身で作成することになると思います。そうすると、自身のアプリで使用されるUserクラスとFirebase Authenticationプラグインで提供されるUserクラスが競合してしまいます。そこでasを用いてFirebase Authenticationのプラグインに名前をつけて参照することでコンフリクトを解消することができます。

    import 'package:firebase_auth/firebase_auth.dart' as firebase_auth;
    
    firebase_auth.User firebaseUser = firebase_auth.User();
    
    User user = User();
    
  • deferred
    はじめまして。すみません、この記事書くまで知りませんでした。

    • 必要になるまで対象ライブラリの読み込みを後回しにします。
    • loadLibrary()で対象ライブラリを読み込みます。
    • loadLibrary()を実行するためにasで名前をつける必要があります。deferredというよりdeferred asかもしれません。
    library_a.dart
    import 'package:library_b/library_b.dart' deffered as library_b;
    
    void main() {
      // library_b.bar();
      foo();
    }
    
    Future foo() async {
      // ここでやっと読み込み
      await library_b.loadLibrary();
      library_b.bar();
    }
    
    library_a.dart
    import 'package:library_b/library_b.dart' deferred as library_b;
    
    void main() {
      library_b.bar(); // ここで呼び出してしまうとエラー
      foo();
    }
    
    Future foo() async {
      await library_b.loadLibrary();
      library_b.bar();
    }
    
    Unhandled exception:
    Deferred library library_b was not loaded.
    
  • 組み合わせ

      library import export part part of
    show
    hide
    as
    deferred

記述スタイル

  • ライブラリ、パッケージ、ディレクトリ、ソースファイル名はスネークケースで命名する[6]

    // Good
    library peg_parser.source_scanner;
    
    import 'file_system.dart';
    import 'slider_menu.dart';
    
    // Bad
    library pegparser.SourceScanner;
    
    import 'file-system.dart';
    import 'SliderMenu.dart';
    
  • プレフィックスを指定してimportする際はスネークケースを用いる[7]

    // Good
    import 'dart:math' as math;
    import 'package:angular_components/angular_components' as angular_components;
    import 'package:js/js.dart' as js;
    
    // Bad
    import 'dart:math' as Math;
    import 'package:angular_components/angular_components' as angularComponents;
    import 'package:js/js.dart' as JS;
    

順番

  • dart:で始まるライブラリはその他のライブラリより前に記述する[8]

    import 'dart:async';
    import 'dart:html';
    
    import 'package:bar/bar.dart';
    import 'package:foo/foo.dart';
    
  • package:で始まるライブラリは相対パスで記述するライブラリより前に記述する[9]

    import 'package:bar/bar.dart';
    import 'package:foo/foo.dart';
    
    import 'util.dart';
    
  • exportimportのセクションより後に切り離して記述する[10]

    // Good
    import 'src/error.dart';
    import 'src/foo_bar.dart';
    
    export 'src/error.dart';
    
    // Bad
    import 'src/error.dart';
    export 'src/error.dart';
    import 'src/foo_bar.dart';
    
  • それぞれのセクション内はアルファベット順に並べる[11]

    // Good
    import 'package:bar/bar.dart';
    import 'package:foo/foo.dart';
    
    import 'foo.dart';
    import 'foo/foo.dart';
    
    // Bad
    import 'package:foo/foo.dart';
    import 'package:bar/bar.dart';
    
    import 'foo/foo.dart';
    import 'foo.dart';
    
  • asshowhideより前に記述する

    // Good
    import 'package:foo/foo.dart' as foo show Hoge hide Fuga;
    
    // Bad
    import 'package:foo/foo.dart' show Hoge hide Fuga as foo;
    

Effective Dart

各ディレクティブの解説の多くは公式ドキュメント内のEffective Dartからの引用です。

Dartに関する様々なガイドが提供されていますのでぜひ読んでみてください。

参考

脚注
  1. Effective Dart: What makes a library package
    ↩︎

  2. Effective Dart: What makes a library package
    ↩︎

  3. Effective Dart: DO use relative paths when importing libraries within your own package’s lib directory. ↩︎

  4. Effective Dart: Organizing a library package ↩︎

  5. Effective Dart: DO name import prefixes using lowercase_with_underscores.
    ↩︎

  6. Effective Dart: DO name libraries, packages, directories, and source files using lowercase_with_underscores. ↩︎

  7. Effective Dart: DO name import prefixes using lowercase_with_underscores.
    ↩︎

  8. Effective Dart: DO place “dart:” imports before other imports. ↩︎

  9. Effective Dart: DO place “package:” imports before relative imports. ↩︎

  10. Effective Dart: DO specify exports in a separate section after all imports. ↩︎

  11. Effective Dart: DO sort sections alphabetically.
    ↩︎