Effective Dart: スタイル
- 識別子- 型には UpperCamelCase を使用する
- 拡張機能には UpperCamelCase を使用する
- パッケージ、ディレクトリ、ソースファイルには lowercase_with_underscores を使用する
- インポートプレフィックスには lowercase_with_underscores を使用する
- その他の識別子には lowerCamelCase を使用する
- 定数名には lowerCamelCase を推奨する
- 2文字より長い頭字語や省略語は、単語のように大文字にする
- 使用しないコールバックパラメータにはワイルドカードを推奨する
- プライベートでない識別子に先頭アンダースコアを使用しない
- プレフィックス文字を使用しない
- ライブラリに明示的な名前を付けない
 
- 順序
- フォーマット
良いコードの驚くほど重要な部分は、良いスタイルです。一貫した命名、順序、フォーマットは、同じである*コード*が同じように*見える*ように役立ちます。これは、私たちのほとんどが目を持っている強力なパターンマッチングハードウェアを活用します。Dartエコシステム全体で一貫したスタイルを使用すると、お互いのコードから学び、貢献することが容易になります。
識別子
#Dart には、3つの種類の識別子があります。
- UpperCamelCase名は、最初の単語を含む各単語の最初の文字を大文字にします。
- lowerCamelCase名は、最初の文字は常に小文字で、最初の単語を除く各単語の最初の文字を大文字にします。たとえそれが頭字語であってもです。
- lowercase_with_underscores名は、頭字語でもすべて小文字を使用し、単語を- _で区切ります。
型には UpperCamelCase を使用する
#リンタールール: camel_case_types
クラス、enum 型、typedef、型パラメータは、最初の単語を含む各単語の最初の文字を大文字にし、区切り文字を使用しないようにします。
class SliderMenu {
   ...
}
class HttpRequest {
   ...
}
typedef Predicate<T> = bool Function(T value);これには、メタデータアノテーションで使用されるクラスも含まれます。
class Foo {
  const Foo([Object? arg]);
}
@Foo(anArg)
class A {
   ...
}
@Foo()
class B {
   ...
}アノテーションクラスのコンストラクタがパラメータを取らない場合、別の lowerCamelCase 定数を作成したくなるかもしれません。
const foo = Foo();
@foo
class C {
   ...
}拡張機能には UpperCamelCase を使用する
#リンタールール: camel_case_extensions
型と同様に、拡張機能は、最初の単語を含む各単語の最初の文字を大文字にし、区切り文字を使用しないようにします。
extension MyFancyList<T> on List<T> {
   ...
}
extension SmartIterable<T> on Iterable<T> {
   ...
}パッケージ、ディレクトリ、ソースファイルには lowercase_with_underscores を使用する
#リンタールール: file_names, package_names
一部のファイルシステムは、大文字と小文字を区別しないため、多くのプロジェクトではファイル名をすべて小文字にする必要があります。区切り文字を使用すると、その形式でも名前を読みやすくできます。アンダースコアを区切り文字として使用すると、名前は有効な Dart 識別子のままになり、将来的に言語がシンボリックインポートをサポートする場合に役立つ可能性があります。
my_package
└─ lib
   └─ file_system.dart
   └─ slider_menu.dartmypackage
└─ lib
   └─ file-system.dart
   └─ SliderMenu.dartインポートプレフィックスには lowercase_with_underscores を使用する
#リンタールール: library_prefixes
import 'dart:math' as math;
import 'package:angular_components/angular_components.dart' as angular_components;
import 'package:js/js.dart' as js;import 'dart:math' as Math;
import 'package:angular_components/angular_components.dart' as angularComponents;
import 'package:js/js.dart' as JS;その他の識別子には lowerCamelCase を使用する
#リンタールール: non_constant_identifier_names
クラスメンバー、トップレベル定義、変数、パラメータ、名前付きパラメータは、最初の単語を除く各単語の最初の文字を大文字にし、区切り文字を使用しないようにします。
var count = 3;
HttpRequest httpRequest;
void align(bool clearItems) {
  // ...
}定数名には lowerCamelCase を推奨する
#リンタールール: constant_identifier_names
新しいコードでは、enum 値を含む定数変数に lowerCamelCase を使用します。
const pi = 3.14;
const defaultTimeout = 1000;
final urlScheme = RegExp('^([a-z]+):');
class Dice {
  static final numberGenerator = Random();
}const PI = 3.14;
const DefaultTimeout = 1000;
final URL_SCHEME = RegExp('^([a-z]+):');
class Dice {
  static final NUMBER_GENERATOR = Random();
}既存のコードとの一貫性のために、以下のような場合に SCREAMING_CAPS を使用できます。
- 既存のコードが SCREAMING_CAPSを使用しているファイルまたはライブラリにコードを追加する場合。
- Java コードと並行して Dart コードを生成する場合。たとえば、protobuf から生成された enum 型など。
2文字より長い頭字語や省略語は、単語のように大文字にする
#大文字の頭字語は読みにくく、複数の隣接する頭字語は曖昧な名前につながる可能性があります。たとえば、識別子 HTTPSFTP が与えられた場合、リーダーはそれが HTTPS FTP または HTTP SFTP を参照しているかどうかを判断できません。これを避けるために、ほとんどの頭字語と省略語は、通常の単語のように大文字にします。この識別子は、後者の場合は HttpsFtp、前者の場合は HttpSftp になります。
2文字の省略語と頭字語は例外です。英語で両方の文字が大文字の場合、識別子で使用するときは両方とも大文字のままにする必要があります。それ以外の場合は、単語のように大文字にします。
// Longer than two letters, so always like a word:
Http // "hypertext transfer protocol"
Nasa // "national aeronautics and space administration"
Uri // "uniform resource identifier"
Esq // "esquire"
Ave // "avenue"
// Two letters, capitalized in English, so capitalized in an identifier:
ID // "identifier"
TV // "television"
UI // "user interface"
// Two letters, not capitalized in English, so like a word in an identifier:
Mr // "mister"
St // "street"
Rd // "road"HTTP // "hypertext transfer protocol"
NASA // "national aeronautics and space administration"
URI // "uniform resource identifier"
esq // "esquire"
ave // "avenue"
Id // "identifier"
Tv // "television"
Ui // "user interface"
MR // "mister"
ST // "street"
RD // "road"lowerCamelCase 識別子の先頭に省略語のいずれかの形式が来る場合、省略語はすべて小文字にする必要があります。
var httpConnection = connect();
var tvSet = Television();
var mrRogers = 'hello, neighbor';使用しないコールバックパラメータにはワイルドカードを推奨する
#コールバック関数の型シグネチャにパラメータが必要な場合がありますが、コールバックの実装ではそのパラメータを*使用しません*。この場合、使用しないパラメータに _ という名前を付けるのが慣習です。これは、束縛されない ワイルドカード変数 を宣言します。
futureOfVoid.then((_) {
  print('Operation complete.');
});ワイルドカード変数は束縛されないため、複数の使用しないパラメータに _ という名前を付けることができます。
.onError((_, _) {
  print('Operation failed.');
});このガイドラインは、*匿名でローカル*な関数にのみ適用されます。これらの関数は通常、使用しないパラメータが何を表しているかが明確なコンテキストで直接使用されます。対照的に、トップレベル関数やメソッド宣言にはそのコンテキストがないため、パラメータには、たとえ使用されていなくても、各パラメータが何であるかが明確になるように名前を付ける必要があります。
プライベートでない識別子に先頭アンダースコアを使用しない
#Dart は、識別子に先頭アンダースコアを使用して、メンバーやトップレベル宣言をプライベートとしてマークします。これにより、ユーザーは先頭アンダースコアをこれらの宣言のいずれかの種類に関連付けることができます。彼らは "_" を見て、「プライベート」と考えます。
ローカル変数、パラメータ、ローカル関数、またはライブラリプレフィックスには「プライベート」という概念はありません。これらの名前のいずれかの先頭にアンダースコアが付いていると、リーダーに混乱を招くシグナルが送信されます。それを避けるために、これらの名前に先頭アンダースコアを使用しないでください。
プレフィックス文字を使用しない
#ハンガリアン記法 やその他のスキームは、コンパイラがコードの理解を助けるためにあまり行わなかった BCPL の時代に生まれました。Dart は宣言の型、スコープ、可変性、その他のプロパティを伝えることができるため、識別子名にこれらのプロパティをエンコードする必要はありません。
defaultTimeoutkDefaultTimeoutライブラリに明示的な名前を付けない
#library ディレクティブに名前を付けることは技術的には可能ですが、レガシー機能であり推奨されません。
Dart は、パスとファイル名に基づいて各ライブラリに一意のタグを生成します。ライブラリに名前を付けると、この生成された URI が上書きされます。URI がないと、ツールが関連するメインライブラリファイルを特定することが難しくなる可能性があります。
library my_library;/// A really great test library.
@TestOn('browser')
library;順序
#ファイルの先頭部分をすっきりと保つために、ディレクティブが表示される順序が規定されています。各「セクション」は空行で区切る必要があります。
すべての順序付けガイドラインは、1つのリンタールールで処理されます: directives_ordering.
dart: インポートは他のインポートより前に配置する
#リンタールール: directives_ordering
import 'dart:async';
import 'dart:collection';
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';package: インポートは相対インポートより前に配置する
#リンタールール: directives_ordering
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';
import 'util.dart';エクスポートは、すべてのインポートの後に別のセクションで指定する
#リンタールール: directives_ordering
import 'src/error.dart';
import 'src/foo_bar.dart';
export 'src/error.dart';import 'src/error.dart';
export 'src/error.dart';
import 'src/foo_bar.dart';セクションはアルファベット順に並べる
#リンタールール: directives_ordering
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';
import 'foo.dart';
import 'foo/foo.dart';import 'package:foo/foo.dart';
import 'package:bar/bar.dart';
import 'foo/foo.dart';
import 'foo.dart';フォーマット
#多くの言語と同様に、Dart は空白を無視します。しかし、*人間*はそうしません。一貫した空白スタイルを持つことは、人間がコードをコンパイラと同じように見ることを保証するのに役立ちます。
コードは dart format を使用してフォーマットする
#フォーマットは退屈な作業であり、リファクタリング中は特に時間がかかります。幸いなことに、心配する必要はありません。dart format という洗練された自動コードフォーマッターを提供しており、それがあなたの代わりにそれを行います。Dart の公式の空白処理ルールは、*dart format が生成するものは何でも*です。 フォーマッター FAQ は、それが強制するスタイル選択についてさらに洞察を提供できます。
残りのフォーマットガイドラインは、dart format では修正できない数少ない項目に関するものです。
フォーマッターフレンドリーにするためにコードを変更することを検討する
#フォーマッターは、どのようなコードでも最善を尽くしますが、奇跡は起こせません。コードに特に長い識別子、深くネストされた式、さまざまな種類の演算子の混合などがある場合、フォーマットされた出力は依然として読みにくい場合があります。
そのような場合は、コードを再編成または単純化してください。ローカル変数の名前を短くすることや、式を新しいローカル変数にホイスティングすることを検討してください。言い換えれば、コードを手動でフォーマットして読みやすくしようとした場合と同じ種類の変更を行います。dart format を、美しいコードを作成するために、時には反復的に協力するパートナーと考えてください。
行は80文字以下を推奨する
#リンタールール: lines_longer_than_80_chars
可読性に関する調査によると、長いテキスト行は、次の行の先頭に移動するときに目がより遠くまで移動する必要があるため、読みにくいことが示されています。これは、新聞や雑誌が複数のコラムのテキストを使用する理由です。
本当に80文字を超える行が必要だと感じる場合は、経験上、コードが冗長すぎてもう少しコンパクトにできる可能性があります。主な原因は通常 VeryLongCamelCaseClassNames です。自問してください。「その型名の各単語は、重要なことを伝えていますか、それとも名前の衝突を防いでいますか?」そうでない場合は、省略を検討してください。
dart format はデフォルトで80文字以下になりますが、設定でデフォルトを変更できます。長い文字列リテラルを80文字に収まるように分割しないため、手動で行う必要があります。
例外: URI またはファイルパスがコメントまたは文字列 (通常はインポートまたはエクスポート内) に出現する場合、行が80文字を超える原因となっても、そのまま保持されることがあります。これにより、ソースファイルでパスを検索しやすくなります。
例外: 改行が文字列内で意味を持つため、複数行文字列には80文字を超える行を含めることができます。行を短いものに分割すると、プログラムが変更される可能性があります。
すべてのフロー制御ステートメントで波括弧を使用する
#リンタールール: curly_braces_in_flow_control_structures
これにより、dangling else 問題が回避されます。
if (isWeekDay) {
  print('Bike to work!');
} else {
  print('Go dancing or read a book!');
}例外: else 句がなく、if ステートメント全体が1行に収まる場合は、必要に応じて波括弧を省略できます。
if (arg == null) return defaultValue;ただし、本文が次の行に折り返される場合は、波括弧を使用します。
if (overflowChars != other.overflowChars) {
  return overflowChars < other.overflowChars;
}if (overflowChars != other.overflowChars)
  return overflowChars < other.overflowChars;