Effective Dart: StyleをGoogleさんで翻訳
優れたコードの重要な部分は、良いスタイルです。一貫した命名、順序付け、およびフォーマットは、同じコードが同じように見えるのに役立ちます。これは、私たちのほとんどが視覚系に備えている強力なパターンマッチングハードウェアを利用しています。Dartエコシステム全体で一貫したスタイルを使用すると、私たち全員がお互いのコードから学び、貢献することが容易になります。
識別子
Dartには3つのフレーバー識別子があります。
-
UpperCamelCase
の名前は、最初の文字を含む各単語の最初の文字を大文字にします。 -
lowerCamelCase
の名前は、常に小文字の頭字語以外の各単語の最初の文字を大文字にします。 -
lowercase_with_underscores
の名前は、頭字語の場合でも小文字のみを使用し、単語を_で区切ります。
UpperCamelCase
を使用して名前タイプを実行します。
クラス、列挙型、typedef、および型パラメーターは、各単語の最初の文字(最初の単語を含む)を大文字にし、区切り文字を使用しないでください。
// good
class SliderMenu { ... }
class HttpRequest { ... }
typedef Predicate<T> = bool Function(T value);
これには、メタデータ注釈で使用することを目的としたクラスも含まれます。
// good
class Foo {
const Foo([Object? arg]);
}
@Foo(anArg)
class A { ... }
@Foo()
class B { ... }
アノテーションクラスのコンストラクターがパラメーターを受け取らない場合は、別のlowerCamelCase
定数を作成することをお勧めします。
// good
const foo = Foo();
@foo
class C { ... }
UpperCamelCase
を使用して名前拡張子を付けます。
タイプと同様に拡張機能は、各単語の最初の文字(最初の単語を含む)を大文字にし、区切り文字を使用しないでください。
// good
extension MyFancyList<T> on List<T> { ... }
extension SmartIterable<T> on Iterable<T> { ... }
lowercase_with_underscores
を使用して、ライブラリ、パッケージ、ディレクトリ、およびソースファイルに名前を付けます。
一部のファイルシステムでは大文字と小文字が区別されないため、多くのプロジェクトではファイル名をすべて小文字にする必要があります。区切り文字を使用すると、名前をその形式で引き続き読み取ることができます。区切り文字としてアンダースコアを使用すると、名前が引き続き有効なDart識別子であることが保証されます。これは、言語が後でシンボリックインポートをサポートする場合に役立つことがあります。
// 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';
注:このガイドラインは、ライブラリに名前を付けることを選択した場合に、ライブラリに名前を付ける方法を指定します。 必要に応じて、ファイル内のライブラリディレクティブを省略してもかまいません。
lowercase_with_underscoresを使用してインポートプレフィックスに名前を付けます。
// 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;
lowerCamelCase
を使用して他の識別子に名前を付けてください。
クラスメンバー、最上位の定義、変数、パラメーター、および名前付きパラメーターは、最初の単語を除く各単語の最初の文字を大文字にし、区切り文字を使用しないでください。
// good
var count = 3;
HttpRequest httpRequest;
void align(bool clearItems) {
// ...
}
定数名にlowerCamelCase
を使用することをお勧めします。
新しいコードでは、列挙値を含む定数変数にlowerCamelCaseを使用します。
// good
const pi = 3.14;
const defaultTimeout = 1000;
final urlScheme = RegExp('^([a-z]+):');
class Dice {
static final numberGenerator = Random();
}
// bad
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コードを生成する場合(たとえば、protobufsから生成された列挙型)。
注:最初は、定数にJavaの
SCREAMING_CAPS
スタイルを使用していました。 いくつかの理由で変更しました。
SCREAMING_CAPS
は、多くの場合、特にCSSカラーなどの列挙値では見栄えがよくありません。- 多くの場合、定数は最終的な非定数変数に変更されるため、名前を変更する必要があります。
- 列挙型で自動的に定義される
values
プロパティは、constで小文字です。
単語のように2文字より長い頭字語と略語を大文字にしてください。
大文字の頭字語は読みにくい場合があり、隣接する複数の頭字語はあいまいな名前につながる可能性があります。たとえば、HTTPSFTP
で始まる名前を指定すると、それがHTTPS FTPとHTTP SFTPのどちらを指しているのかを判断する方法はありません。
これを回避するために、頭字語と略語は通常の単語のように大文字になります。
例外:IO(入力/出力)のような2文字の頭字語は完全に大文字になっています:IO
。一方、ID(識別)のような2文字の略語は、通常の単語のように大文字で表記されます。Id
。
// good
class HttpConnection {}
class DBIOPort {}
class TVVcr {}
class MrRogers {}
var httpRequest = ...
var uiHandler = ...
Id id;
// bad
class HTTPConnection {}
class DbIoPort {}
class TvVcr {}
class MRRogers {}
var hTTPRequest = ...
var uIHandler = ...
ID iD;
未使用のコールバックパラメータには、_などを使用することをお勧めします。
コールバック関数の型シグネチャにパラメータが必要な場合がありますが、コールバックの実装ではパラメータを使用しません。この場合、未使用のパラメータにという名前を付けるのは慣用的です。関数に未使用のパラメーターが複数ある場合は、名前の衝突を避けるために追加のアンダースコアを使用します:、__など。
// good
futureOfVoid.then((_) {
print('Operation complete.');
});
このガイドラインは、匿名とローカルの両方の機能のみを対象としています。これらの関数は通常、未使用のパラメータが何を表しているのかが明確な状況ですぐに使用されます。対照的に、最上位の関数とメソッド宣言にはそのコンテキストがないため、使用されていない場合でも、各パラメーターの目的が明確になるようにパラメーターに名前を付ける必要があります。
プライベートではない識別子には、先頭にアンダースコアを使用しないでください。
Dartは、識別子の先頭にアンダースコアを使用して、メンバーとトップレベルの宣言をプライベートとしてマークします。これにより、先頭のアンダースコアをこれらの種類の宣言の1つに関連付けるようにユーザーがトレーニングされます。 彼らは「_」を見て「プライベート」と考えます。
ローカル変数、パラメーター、ローカル関数、またはライブラリプレフィックスの「プライベート」の概念はありません。それらの1つにアンダースコアで始まる名前がある場合、それはリーダーに紛らわしい合図を送ります。これを回避するには、これらの名前に先頭の下線を使用しないでください。
プレフィックス文字を使用しないでください。
ハンガリアン記法やその他のスキームは、コンパイラがコードを理解するのにあまり役立たなかったBCPLの時代に生まれました。Dartは宣言のタイプ、スコープ、可変性、およびその他のプロパティを教えてくれるので、これらのプロパティを識別子名でエンコードする理由はありません。
// good
defaultTimeout
// bad
kDefaultTimeout
注文
ファイルのプリアンブルを整理するために、ディレクティブが表示される順序が規定されています。各「セクション」は空白行で区切る必要があります。
単一のリンタールールがすべての順序付けガイドラインを処理します:directives_ordering。
「dart:」インポートを他のインポートの前に配置してください。
// good
import 'dart:async';
import 'dart:html';
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';
相対インポートの前に「package:」インポートを配置してください。
// good
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';
import 'util.dart';
すべてのインポートの後に、別のセクションでエクスポートを指定してください。
// 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';
セクションをアルファベット順に並べ替えます。
// 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';
書式設定
多くの言語と同様に、ダートは空白を無視します。 しかし、人間はそうではありません。 一貫した空白のスタイルを持つことは、人間の読者がコンパイラーと同じようにコードを見るのを確実にするのに役立ちます。
dartフォーマット
を使用してコードをフォーマットしてください。
フォーマットは面倒な作業であり、リファクタリング中に特に時間がかかります。幸い、心配する必要はありません。私たちはあなたのためにそれを行うdartフォーマットと呼ばれる洗練された自動コードフォーマッターを提供します。適用されるルールに関するドキュメントがいくつかありますが、Dartの公式の空白処理ルールは、dartフォーマット
で生成されるものです。
残りのフォーマットガイドラインは、ダートフォーマット
で修正できないいくつかのことに関するものです。
コードをよりフォーマッターに適したものにするためにコードを変更することを検討してください。
フォーマッターは、どのコードをスローしても可能な限り最善を尽くしますが、奇跡を起こすことはできません。コードに特に長い識別子、深くネストされた式、さまざまな種類の演算子が混在している場合など、フォーマットされた出力は依然として読みにくい場合があります。
その場合は、コードを再編成または簡略化してください。ローカル変数名を短くするか、式を新しいローカル変数に引き上げることを検討してください。つまり、コードを手動でフォーマットして読みやすくしようとした場合と同じ種類の変更を加えます。ダートフォーマット
は、美しいコードを作成するために、時には繰り返し協力して作業するパートナーシップと考えてください。
80文字を超える行は避けてください。
読みやすさの調査によると、次の行の先頭に移動するときに目が遠くに移動する必要があるため、長いテキスト行は読みにくくなります。 これが、新聞や雑誌が複数列のテキストを使用する理由です。
80文字を超える行が本当に必要な場合は、コードが冗長すぎる可能性があり、もう少しコンパクトになる可能性があります。主な違反者は通常、VeryLongCamelCaseClassNames
です。「そのタイプ名の各単語は、重要なことを教えてくれますか、それとも名前の衝突を防ぎますか?」と自問してください。 そうでない場合は、省略することを検討してください。
例外:コメントにURIまたはファイルパスが含まれている場合、または文字列(通常はインポートまたはエクスポート)は行が80文字を超えても、全体が残る場合があります。これにより、ソースファイルでパスを簡単に検索できます。
例外:複数行の文字列には80文字を超える行を含めることができます。これは、文字列内で改行が重要であり、行を短い行に分割するとプログラムが変更される可能性があるためです。
すべてのフロー制御ステートメントには中括弧を使用してください。
そうすることで、他のぶら下がりの問題を回避できます。
// good
if (isWeekDay) {
print('Bike to work!');
} else {
print('Go dancing or read a book!');
}
例外:else句のないifステートメントがあり、ifステートメント全体が1行に収まる場合は、必要に応じて中括弧を省略できます。
// good
if (arg == null) return defaultValue;
ただし、本文が次の行に折り返される場合は、中かっこを使用してください。
// good
if (overflowChars != other.overflowChars) {
return overflowChars < other.overflowChars;
}
// bad
if (overflowChars != other.overflowChars)
return overflowChars < other.overflowChars;