Dartのディレクティブたち
ディレクティブという単語がそれらのみを指しているのかわかりませんが、import
やexport
などのライブラリの読み込みに関する単語のまとめです。
普段import
とas
ぐらいしか使わないけど、そういえばいろいろあったよなーと思い、まとめ始めたらなんか知らないのまで出てきました。
ディレクティブたち
-
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 thelibrary
directive from your code unless you plan to generate library-level documentation.
library my_library; // 省略可
-
import
- ライブラリを読み込むために使用します。
- 同じパッケージ内のライブラリ(自身がいる
lib
内にある別のライブラリ)を読み込む時はpackage:
で始まる明示的なパスで指定せず、相対パスを使用する。[3]
lib/my_library.dartimport 'package:my_package/src/other_library.dart'; // Bad import 'src/other_library.dart'; // Good
-
export
- 外部に公開するライブラリを指定するために使用します。メインのライブラリに
export
を記述することで、メインのライブラリを読み込むだけでexport
で指定されたライブラリにもアクセスできます。
lib/my_library.dartexport 'src/foo.dart'; export 'src/bar.dart';
someones_library.dartimport 'package:my_library/my_library.dart'; void main() { foo(); // foo.dart内にある関数 bar(); // bar.dart内にある関数 }
- 外部に公開するライブラリを指定するために使用します。メインのライブラリに
-
part
- 後述の
part of
とセットで使用されます。 - 一つのライブラリを複数のファイルに分割するために使用します。
- 公式からは
part
とpart 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 usingpart
and create mini libraries instead.
my_library.dartlibrary my_library; part 'src/part_a.dart'; part 'src/part_b.dart';
- 後述の
-
part of
- 先述の
part
とセットで使用されます。 - 一つのライブラリを複数のファイルに分割するために使用します。
-
part of
ディレクティブはDartの歴史的理由でそれ自身が属している(part ofである)ライブラリの名前を使用できるようですが、他のディレクティブと同様にそのライブラリへのパスを文字列で指定することが推奨されています。[5]
part of my_library; // Bad part of '../../my_library.dart'; // Good
part_a.dartpart of '../../my_library.dart';
part_b.dartpart of '../../my_library.dart';
- 先述の
オプション的なものたち
-
show
- 指定したクラスや関数のみを参照します。
import 'package:other_package/other_package.dart' show SomeClass;
-
hide
- 指定したクラスや関数を参照しないようにします。
import 'package:other_package/other_package.dart' hide SomeClass;
-
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.dartimport '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.dartimport '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';
-
export
はimport
のセクションより後に切り離して記述する[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';
-
as
はshow
とhide
より前に記述する// 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に関する様々なガイドが提供されていますのでぜひ読んでみてください。
参考
-
Effective Dart: DO use relative paths when importing libraries within your own package’s lib directory. ↩︎
-
Effective Dart: DO name import prefixes using lowercase_with_underscores.
↩︎ -
Effective Dart: DO name libraries, packages, directories, and source files using lowercase_with_underscores. ↩︎
-
Effective Dart: DO name import prefixes using lowercase_with_underscores.
↩︎ -
Effective Dart: DO place “dart:” imports before other imports. ↩︎
-
Effective Dart: DO place “package:” imports before relative imports. ↩︎
-
Effective Dart: DO specify exports in a separate section after all imports. ↩︎
Discussion