Effective Dart: Style
Effective Dart: Style

Привет, если вы на пути изучения Flutter/Dart или вам просто интересно почитать про путь изучения, подписывайтесь на мой канал в telegram, буду рад вас видеть! А сегодня поговорим про руководство по стилю в Dart!

Содержание:

Удивительно важной частью хорошего кода является хороший стиль. Согласованное присвоение имен, упорядочение и форматирование помогают одинаковому коду выглядеть одинаково. В нем используются преимущества мощного аппаратного обеспечения для сопоставления с образцом, которое есть у большинства из нас в наших зрительных системах. Если мы используем единый стиль во всей экосистеме Dart, всем нам будет легче учиться на коде друг друга и вносить свой вклад в него.

Идентификаторы

Идентификаторы в Dart бывают трех видов.

  • В названиях UpperCamelCase заглавными буквами пишутся первые буквы каждого слова, включая первую.

  • В названиях lowerCamelCase заглавными буквами пишется первая буква каждого слова, за исключением первой, которая всегда пишется строчными буквами, даже если это аббревиатура.

  • в именах lowercase_with_underscores используются только строчные буквы, даже для сокращений, и разделяются слова символом _.

DO типы имен используя UpperCamelCase

Правило Линтера: camel_case_types

Классы, enum типы, typedefs и параметры типа должны содержать заглавную букву каждого слова (включая первое слово) и не использовать разделителей.

?хорошо

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 { ... }

DO расширения имен, используя UpperCamelCase

Правило Линтер: camel_case_extensions

Как и в типах, в расширениях первая буква каждого слова должна быть заглавной (включая первое слово) и не использовать разделителей.

?хорошо

extension MyFancyList<T> on List<T> { ... }

extension SmartIterable<T> on Iterable<T> { ... }

DO имена пакетов, каталогов и исходных файлов, используя lowercase_with_underscores

Правила Линтер: file_names, package_names

Некоторые файловые системы не учитывают регистр, поэтому во многих проектах требуется, чтобы все имена файлов были строчными. Использование разделительного символа позволяет именам оставаться читаемыми в таком виде. Использование подчеркивания в качестве разделителя гарантирует, что имя по-прежнему является допустимым идентификатором Dart, что может быть полезно, если язык позже поддержит символьный импорт.

?хорошо

my_package
└─ lib
   └─ file_system.dart
   └─ slider_menu.dart

?плохо

mypackage
└─ lib
   └─ file-system.dart
   └─ SliderMenu.dart

DO имена import префиксов с использованием 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;

DO именуйте другие идентификаторы, используя lowerCamelCase

Правило Линтер: non_constant_identifier_names

Члены класса, определения верхнего уровня, переменные, параметры и именованные параметры должны начинаться с заглавной буквы каждого слова, за исключением первого слова, и не использовать разделителей.

?хорошо

var count = 3;

HttpRequest httpRequest;

void align(bool clearItems) {
  // ...
}

PREFER используйте lowerCamelCase для имен констант

Правило Линтер: constant_identifier_names

В новом коде используйте 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.

  • При генерации кода Dart, параллельного коду Java, например, в перечисляемых типах, сгенерированных из protobufs.

⚠️ Изначально мы использовали стиль Java SCREAMING_CAPS для констант. Мы изменили его по нескольким причинам:

  • SCREAMING_CAPS во многих случаях выглядит плохо, особенно перечислимые значения для таких вещей, как цвета CSS.

  • Константы часто заменяются конечными неконстантными переменными, что потребовало бы изменения имени.

  • Свойство values, автоматически определяемое для типа enum, имеет значение const и нижний регистр.

DO используйте заглавные буквы в аббревиатурах и сокращениях длиной более двух букв

Аббревиатуры с заглавной буквы могут быть трудночитаемыми, а несколько соседних аббревиатур могут привести к неоднозначным названиям. Например, учитывая имя, начинающееся с HTTPSFTP, невозможно определить, относится ли оно к HTTPS FTP или HTTP SFTP.

Чтобы избежать этого, сокращения пишутся с заглавной буквы, как обычные слова.

Исключение: Двухбуквенные сокращения, такие как IO (ввод/вывод), пишутся полностью с заглавной буквы: IO. С другой стороны, двухбуквенные сокращения, такие как ID (идентификация), по-прежнему пишутся с заглавной буквы, как обычные слова: Id.

?хорошо

class HttpConnection {}
class DBIOPort {}
class TVVcr {}
class MrRogers {}

var httpRequest = ...
var uiHandler = ...
var userId = ...
Id id;

?плохо

class HTTPConnection {}
class DbIoPort {}
class TvVcr {}
class MRRogers {}

var hTTPRequest = ...
var uIHandler = ...
var userID = ...
ID iD;

PREFER используя _, __ и т.д. для неиспользуемых параметров обратного вызова

Иногда сигнатура типа функции обратного вызова требует параметра, но реализация обратного вызова этот параметр не использует. В этом случае идиоматично называть неиспользуемый параметр _. Если функция имеет несколько неиспользуемых параметров, используйте дополнительные символы подчеркивания, чтобы избежать коллизий имен: _, __ и т.д.

?хорошо

futureOfVoid.then((_) {
  print('Operation complete.');
});

Это руководство предназначено только для функций, которые являются как анонимными, так и локальными. Эти функции обычно используются непосредственно в контексте, где ясно, что представляет собой неиспользуемый параметр. Напротив, функции верхнего уровня и объявления методов не имеют такого контекста, поэтому их параметры должны быть названы так, чтобы было ясно, для чего предназначен каждый параметр, даже если он не используется.

DON’T не используйте начальное подчеркивание для идентификаторов, которые не являются частными

Dart использует начальное подчеркивание в идентификаторе, чтобы пометить элементы и объявления верхнего уровня как частные. Это обучает пользователей связывать начальное подчеркивание с одним из таких типов объявлений. Они видят "_" и думают "private".

Не существует понятия "private" для локальных переменных, параметров, локальных функций или библиотечных префиксов. Когда у одной из них есть имя, начинающееся с подчеркивания, это посылает читателю сбивающий с толку сигнал. Чтобы избежать этого, не используйте начальные символы подчеркивания в этих именах.

DON’T не используйте префиксные буквы

Венгерская нотация и другие схемы возникли во времена BCPL, когда компилятор мало что делал, чтобы помочь вам понять ваш код. Поскольку Dart может сообщить вам тип, область видимости, изменяемость и другие свойства ваших объявлений, нет причин кодировать эти свойства в именах идентификаторов.

?хорошо

defaultTimeout

?плохо

kDefaultTimeout

DON’T не присваивайте библиотекам явных имен

Добавление имени к директиве library технически возможно, но является устаревшей функцией и не рекомендуется.

Dart генерирует уникальный тег для каждой библиотеки на основе ее пути и имени файла. Присвоение имен библиотекам переопределяет этот сгенерированный URI. Без URI инструментам может быть сложнее найти основной файл библиотеки, о котором идет речь.

?плохо

library my_library;

?хорошо

/// A really great test library.
@TestOn('browser')
library;

Чтобы сохранить порядок в преамбуле вашего файла, у нас есть предписанный порядок, в котором должны отображаться директивы. Каждый "раздел" должен быть разделен пустой строкой.

Одно правило компоновки обрабатывает все рекомендации по упорядочению: directives_ordering.

DO размещайте dart: imports перед другими imports

Правило Линтер: directives_ordering

?хорошо

import 'dart:async';
import 'dart:html';

import 'package:bar/bar.dart';
import 'package:foo/foo.dart';

DO размещайте package: imports перед другими imports

Правило Линтер: directives_ordering

?хорошо

import 'package:bar/bar.dart';
import 'package:foo/foo.dart';

import 'util.dart';

DO укажите экспорт в отдельном разделе после всего импорта

Правило Линтер: 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';

DO сортировка разделов в алфавитном порядке

Правило Линтер: 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.

Остальные рекомендации по форматированию касаются тех немногих вещей, которые dart format не может исправить за вас.

CONSIDER подумайте об изменении своего кода, чтобы сделать его более удобным для форматирования

Форматировщик делает все возможное с любым кодом, который вы ему вводите, но он не может творить чудеса. Если в вашем коде особенно длинные идентификаторы, глубоко вложенные выражения, смесь различных типов операторов и т.д. отформатированный вывод все еще может быть трудночитаемым.

Когда это произойдет, реорганизовывайте или упростите свой код. Рассмотрите возможность сокращения имени локальной переменной или переноса выражения в новую локальную переменную. Другими словами, внесите те же изменения, которые вы бы внесли, если бы форматировали код вручную и пытались сделать его более читабельным. Думайте о dart format как о партнерстве, в котором вы работаете вместе, иногда итеративно, над созданием красивого кода.

AVOID избегайте строк длиной более 80 символов

Правило линтера: lines_longer_than_80_chars

Исследования удобочитаемости показывают, что длинные строки текста труднее читать, потому что вашему глазу приходится перемещаться дальше при переходе к началу следующей строки. Вот почему газеты и журналы используют несколько колонок текста.

Если вам действительно нужны строки длиной более 80 символов, наш опыт показывает, что ваш код, скорее всего, слишком многословен и мог бы быть немного компактнее. Основным нарушителем обычно являются VeryLongCamelCaseClassNames. Спросите себя: "Сообщает ли мне каждое слово в названии этого типа что-то важное или предотвращает конфликт имен?" Если нет, подумайте о том, чтобы опустить его.

Обратите внимание, что dart format выполняет 99% этого за вас, но последний 1% - это вы сами. Он не разбивает длинные строковые литералы так, чтобы они помещались в 80 столбцов, поэтому вам придется сделать это вручную.

Исключение: Когда URI или путь к файлу встречается в комментарии или строке (обычно при импорте или экспорте), он может остаться целым, даже если длина строки превышает 80 символов. Это упрощает поиск пути к исходным файлам.

Исключение: Многострочные строки могут содержать строки длиной более 80 символов, поскольку новые строки являются значимыми внутри строки, а разбиение строк на более короткие может привести к изменению программы.

DO используйте фигурные скобки для всех операторов управления потоком

Правило линтера: curly_braces_in_flow_control_structures

Это позволяет избежать проблемы с зависанием else.

?хорошо

if (isWeekDay) {
  print('Bike to work!');
} else {
  print('Go dancing or read a book!');
}

Исключение: Когда у вас есть оператор if без предложения else и весь оператор if помещается в одной строке, вы можете опустить фигурные скобки, если предпочитаете:

?хорошо

if (arg == null) return defaultValue;

Однако, если тело переходит к следующей строке, используйте фигурные скобки:

?хорошо

if (overflowChars != other.overflowChars) {
  return overflowChars < other.overflowChars;
}

?плохо

if (overflowChars != other.overflowChars)
  return overflowChars < other.overflowChars;

Комментарии (1)


  1. webhamster
    26.03.2024 11:37

    Удивительно важной частью хорошего кода является хороший стиль. Согласованное присвоение имен, упорядочение и форматирование помогают одинаковому коду выглядеть одинаково. В нем используются преимущества мощного аппаратного обеспечения для сопоставления с образцом, которое есть у большинства из нас в наших зрительных системах. Если мы используем единый стиль во всей экосистеме Dart, всем нам будет легче учиться на коде друг друга и вносить свой вклад в него.

    Такое впечатление, что писала нейросетка.