Правила флаттер-лайнера Часть 1: Правила ошибок 💫 🌌 ✨

«Где есть правила, там есть закон».

Что такое линтинг?

Линтинг — это процесс проверки исходного кода на наличие программных, стилистических ошибок и неформатированного кода. Он помогает выявить некоторые распространенные и редкие ошибки, допущенные при кодировании, такие как логические ошибки, неиспользуемые переменные, пустые операторы if-else.

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

Правила Линтера делятся на 3 группы. Это

  1. Ошибки: Возможные ошибки кодирования.
  2. Стиль.
  3. Паб: Возможные проблемы с установкой пакета pub .

Каждое правило также имеет уровень зрелости.

Уровни зрелости правил также делятся на 3. К ним относятся:

Стабильный-стабильный
Эти правила безопасны для использования и проверены на работоспособность с последними версиями языка Dart. Все правила считаются стабильными, если они не помечены как экспериментальные или устаревшие.

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

Deprecated-Deprecated
Эти правила больше не рекомендуются для использования и могут быть удалены в будущем выпуске linter.

Правила ошибок

Правила ошибок определяют возможные ошибки и другие погрешности в вашем коде.

Всегда_использовать_пакет_импорта

Избегайте относительного импорта для файлов в lib/.

Обязательно используйте абсолютный импорт для файлов в lib//, чтобы избежать импорта одного и того же члена двумя разными способами.

Правильное использование

import 'package:foo/bar.dart';
import 'package:foo/baz.dart';
import 'package:foo/src/baz.dart';
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

import 'baz.dart';
import 'src/bag.dart'
import '../lib/baz.dart';
Войдите в полноэкранный режим Выход из полноэкранного режима

избегать_динамических_вызовов

Избегайте вызовов методов или доступа к свойствам «динамической» цели.

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

Кроме того, цели с написанием «dynamic» отключают большинство статических анализов.

Неправильное использование

void explicitDynamicType(dynamic object) {
  print(object.foo());
}

void implicitDynamicType(object) {
  print(object.foo());
}

abstract class SomeWrapper {
  T doSomething<T>();
}

void inferredDynamicType(SomeWrapper wrapper) {
  var object = wrapper.doSomething();
  print(object.foo());
}

void callDynamic(dynamic function) {
  function();
}

void functionType(Function function) {
  function();
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void explicitType(Fooable object) {
  object.foo();
}

void castedType(dynamic object) {
  (object as Fooable).foo();
}

abstract class SomeWrapper {
  T doSomething<T>();
}

void inferredType(SomeWrapper wrapper) {
  var object = wrapper.doSomething<Fooable>();
  object.foo();
}

void functionTypeWithParameters(Function() function) {
  function();
}
Войдите в полноэкранный режим Выход из полноэкранного режима

избегать_пустого_удаления

Избегайте пустых операторов else.

Неправильное использование:

if (x > y)
  print("1");
else ;
  print("2");
Войдите в полноэкранный режим Выход из полноэкранного режима

избегать_печати

Избегайте вызовов «print» в производственном коде.

void f(int x) {
  print('debug: $x');
  ...
}
Войдите в полноэкранный режим Выход из полноэкранного режима

избегать_возвращения_нуля_для_будущего

Избегайте возврата null для Future.

избегать_медленного_асинхронного_ио

Избегайте медленных асинхронных методов dart:io.

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

- Directory.exists
- Directory.stat
- File.lastModified
- File.exists
- File.stat
- FileSystemEntity.isDirectory
- FileSystemEntity.isFile
- FileSystemEntity.isLink
- FileSystemEntity.type

Неправильное использование

import 'dart:io';

Future<Null> someFunction() async {
  var file = File('/path/to/my/file');
  var now = DateTime.now();
  if ((await file.lastModified()).isBefore(now)) print('before'); // LINT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

import 'dart:io';

Future<Null> someFunction() async {
  var file = File('/path/to/my/file');
  var now = DateTime.now();
  if (file.lastModifiedSync().isBefore(now)) print('before'); // OK
}
Войдите в полноэкранный режим Выход из полноэкранного режима

избегать_типа_к_строке

Избегайте использования ".toString()" в производственном коде, так как результаты могут быть минимизированы.

Неправильное использование

void bar(Object other) {
  if (other.runtimeType.toString() == 'Bar') {
    doThing();
  }
}

Object baz(Thing myThing) {
  return getThingFromDatabase(key: myThing.runtimeType.toString());
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void bar(Object other) {
  if (other is Bar) {
    doThing();
  }
}

class Thing {
  String get thingTypeKey => ...
}

Object baz(Thing myThing) {
  return getThingFromDatabase(key: myThing.thingTypeKey);
}
Войдите в полноэкранный режим Выход из полноэкранного режима

избегать_типов_как_имени_параметра

Избегайте использования типов в качестве имен параметров.

Неправильное использование: m(f(int));
Правильное использование:
m(f(int v));

избегать_веб_библиотек_в_трепетном_состоянии

Избегайте использования только веб-библиотек, за исключением пакетов веб-плагинов Flutter.

Избегайте использования веб-библиотек, dart:html, dart:js и dart:js_util в пакетах Flutter, которые не являются веб-плагинами. Эти библиотеки не поддерживаются вне веб-контекста; функциональность, которая зависит от них, не будет работать в мобильной среде Flutter, и их использование в Flutter web в целом не рекомендуется.

Доступ к веб-библиотеке разрешен, если

- пакеты плагинов, которые объявляют web в качестве поддерживаемого контекста

в противном случае импорт dart:html, dart:js и dart:js_util не разрешен.

отмена_подписки

Отменить экземпляры dart.async.StreamSubscription.

Отмена экземпляров StreamSubscription предотвращает утечки памяти и неожиданное поведение.

Неправильное использование:

class A {
  StreamSubscription _subscriptionA; // LINT
  void init(Stream stream) {
    _subscriptionA = stream.listen((_) {});
  }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

void someFunction() {
  StreamSubscription _subscriptionF; // LINT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

class B {
  StreamSubscription _subscriptionB; // OK
  void init(Stream stream) {
    _subscriptionB = stream.listen((_) {});
  }

  void dispose(filename) {
    _subscriptionB.cancel();
  }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void someFunctionOK() {
  StreamSubscription _subscriptionB; // OK
  _subscriptionB.cancel();
}
Войдите в полноэкранный режим Выход из полноэкранного режима

закрыть_раковины

Отключение экземпляров Sink предотвращает утечки памяти и неожиданное поведение.

Неправильное использование

class A {
  IOSink _sinkA;
  void init(filename) {
    _sinkA = File(filename).openWrite(); // LINT
  }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

void someFunction() {
  IOSink _sinkF; // LINT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

class B {
  IOSink _sinkB;
  void init(filename) {
    _sinkB = File(filename).openWrite(); // OK
  }

  void dispose(filename) {
    _sinkB.close();
  }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void someFunctionOK() {
  IOSink _sinkFOK; // OK
  _sinkFOK.close();
}
Войдите в полноэкранный режим Выход из полноэкранного режима

комментарии_ссылки

В комментариях к документам ссылайтесь только на идентификаторы области применения.

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

Например:

Правильное использование:

/// [a] veya [b]'den büyük olanı döndürün.
int max_int(int a, int b) { ... }
Войдите в полноэкранный режим Выход из полноэкранного режима

С другой стороны, если предположить, что outOfScopeId выходит за рамки:

Неправильное использование:

/// [value], [outOfScopeId] değerinden büyükse true değerini döndürün.
bool isOutOfRange(int value) { ... }
Войдите в полноэкранный режим Выход из полноэкранного режима

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

- Единичный идентификатор, где идентификатором является любой идентификатор в области действия комментария (см. спецификацию того, что входит в область действия комментариев документа),

- два идентификатора, разделенные точкой, где первый идентификатор - это имя класса в области видимости, а второй - имя члена, объявленного в классе,

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

- или два идентификатора, разделенные точкой и парой круглых скобок, где первый идентификатор - имя класса в области видимости, а второй - имя именованного конструктора (строго не требуется, но допускается для согласованности).

контрольный_поток_в_финале

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

Правильное использование

class Ok {
  double compliantMethod() {
    var i = 5;
    try {
      i = 1 / 0;
    } catch (e) {
      print(e); // OK
    }
    return i;
  }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

class BadReturn {
  double nonCompliantMethod() {
    try {
      return 1 / 0;
    } catch (e) {
      print(e);
    } finally {
      return 1.0; // LINT
    }
  }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

class BadContinue {
  double nonCompliantMethod() {
    for (var o in [1, 2]) {
      try {
        print(o / 0);
      } catch (e) {
        print(e);
      } finally {
        continue; // LINT
      }
    }
    return 1.0;
  }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

class BadBreak {
  double nonCompliantMethod() {
    for (var o in [1, 2]) {
      try {
        print(o / 0);
      } catch (e) {
        print(e);
      } finally {
        break; // LINT
      }
    }
    return 1.0;
  }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

диагностические_описания_всех_свойств
Реализуйте все публичные свойства в отладочных методах.

Реализаторы Diagnosticable должны ссылаться на все публичные свойства в методе debugFillProperties(...) или debugDescribeChildren(...) для улучшения отлаживаемости во время выполнения.

Неправильное использование:

class Absorber extends Widget {
  bool get absorbing => _absorbing;
  bool _absorbing;
  bool get ignoringSemantics => _ignoringSemantics;
  bool _ignoringSemantics;
  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(DiagnosticsProperty<bool>('absorbing', absorbing));
    // Missing reference to ignoringSemantics
  }
}  
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

class Absorber extends Widget {
  bool get absorbing => _absorbing;
  bool _absorbing;
  bool get ignoringSemantics => _ignoringSemantics;
  bool _ignoringSemantics;
  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(DiagnosticsProperty<bool>('absorbing', absorbing));
    properties.add(DiagnosticsProperty<bool>('ignoringSemantics', ignoringSemantics));
  }
}  
Войдите в полноэкранный режим Выход из полноэкранного режима

пустые_заявления

Избегайте пустых заявлений.

Пустые утверждения обычно указывают на ошибку.

Например,

Неправильное использование

if (complicated.expression.foo());
  bar();
Войдите в полноэкранный режим Выход из полноэкранного режима

При форматировании с помощью формата Dart ошибка становится очевидной:

if (complicated.expression.foo()) ;
bar();

Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

if (complicated.expression.foo())
  bar();
Войдите в полноэкранный режим Выход из полноэкранного режима

инвариантные_булевы

Условные выражения не должны безоговорочно оцениваться как true или false.

В настоящее время это правило является экспериментальным (экспериментальным)

Не тестируйте условия, которые могут быть удалены во время компиляции, и не тестируйте одно и то же условие дважды.

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

Неправильное использование

// foo aynı ifadede bara hem eşitdir hem de eşit olamaz
if(foo == bar && something && foo != bar) {...}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

void compute(int foo) {
  if (foo == 4) {
    doSomething();
   // bu noktada foo'nun 4'e eşit olduğunu biliyoruz, bu nedenle sonraki koşul her zaman false
    if (foo > 4) {...}
    ...
  }
  ...
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

void compute(bool foo) {
  if (foo) {
    return;
  }
  doSomething();
  // burada foo'nun değeri her zaman false'dır
  if (foo){...}
  ...
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void nestedOK() {
  if (foo == bar) {
    foo = baz;
    if (foo != bar) {...}
  }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void nestedOk2() {
  if (foo == bar) {
    return;
  }

  foo = baz;
  if (foo == bar) {...} // OK
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void nestedOk5() {
  if (foo != null) {
    if (bar != null) {
      return;
    }
  }

  if (bar != null) {...} // OK
}
Войдите в полноэкранный режим Выход из полноэкранного режима

iterable_contains_unrelated_type

Вызывайте Iterable.contains со ссылками на несвязанные типы.

Неправильное использование:

void someFunction() {
  var list = <int>[];
  if (list.contains('1')) print('someFunction'); // LINT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

void someFunction3() {
  List<int> list = <int>[];
  if (list.contains('1')) print('someFunction3'); // LINT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

void someFunction8() {
  List<DerivedClass2> list = <DerivedClass2>[];
  DerivedClass3 instance;
  if (list.contains(instance)) print('someFunction8'); // LINT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

abstract class SomeIterable<E> implements Iterable<E> {}

abstract class MyClass implements SomeIterable<int> {
  bool badMethod(String thing) => this.contains(thing); // LINT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void someFunction10() {
  var list = [];
  if (list.contains(1)) print('someFunction10'); // OK
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void someFunction1() {
  var list = <int>[];
  if (list.contains(1)) print('someFunction1'); // OK
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void someFunction4() {
  List<int> list = <int>[];
  if (list.contains(1)) print('someFunction4'); // OK
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void someFunction5() {
  List<ClassBase> list = <ClassBase>[];
  DerivedClass1 instance;
  if (list.contains(instance)) print('someFunction5'); // OK
}

abstract class ClassBase {}

class DerivedClass1 extends ClassBase {}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void someFunction6() {
  List<Mixin> list = <Mixin>[];
  DerivedClass2 instance;
  if (list.contains(instance)) print('someFunction6'); // OK
}

abstract class ClassBase {}

abstract class Mixin {}

class DerivedClass2 extends ClassBase with Mixin {}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void someFunction7() {
  List<Mixin> list = <Mixin>[];
  DerivedClass3 instance;
  if (list.contains(instance)) print('someFunction7'); // OK
}

abstract class ClassBase {}

abstract class Mixin {}

class DerivedClass3 extends ClassBase implements Mixin {}
Войдите в полноэкранный режим Выход из полноэкранного режима

list_remove_unrelated_type

Вызывайте remove со ссылками на несвязанные типы.

Не вызывайте метод remove для списка, экземпляр которого имеет тип, отличный от типа параметра.

Это вызывает == для элементов списка и, скорее всего, вернет false.

Неправильное использование

void someFunction() {
  var list = <int>[];
  if (list.remove('1')) print('someFunction'); // LINT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

void someFunction3() {
  List<int> list = <int>[];
  if (list.remove('1')) print('someFunction3'); // LINT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

void someFunction8() {
  List<DerivedClass2> list = <DerivedClass2>[];
  DerivedClass3 instance;
  if (list.remove(instance)) print('someFunction8'); // LINT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

abstract class SomeList<E> implements List<E> {}

abstract class MyClass implements SomeList<int> {
  bool badMethod(String thing) => this.remove(thing); // LINT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void someFunction10() {
  var list = [];
  if (list.remove(1)) print('someFunction10'); // OK
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void someFunction1() {
  var list = <int>[];
  if (list.remove(1)) print('someFunction1'); // OK
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void someFunction4() {
  List<int> list = <int>[];
  if (list.remove(1)) print('someFunction4'); // OK
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void someFunction5() {
  List<ClassBase> list = <ClassBase>[];
  DerivedClass1 instance;
  if (list.remove(instance)) print('someFunction5'); // OK
}

abstract class ClassBase {}

class DerivedClass1 extends ClassBase {}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void someFunction6() {
  List<Mixin> list = <Mixin>[];
  DerivedClass2 instance;
  if (list.remove(instance)) print('someFunction6'); // OK
}

abstract class ClassBase {}

abstract class Mixin {}

class DerivedClass2 extends ClassBase with Mixin {}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void someFunction7() {
  List<Mixin> list = <Mixin>[];
  DerivedClass3 instance;
  if (list.remove(instance)) print('someFunction7'); // OK
}

abstract class ClassBase {}

abstract class Mixin {}

class DerivedClass3 extends ClassBase implements Mixin {}
Войдите в полноэкранный режим Выход из полноэкранного режима

литеральные_только_булевые_выражения
Булево выражение состоит только из литералов.

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

Неправильное использование

void bad() {
  if (true) {} // LINT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

void bad() {
  if (true && 1 != 0) {} // LINT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

void bad() {
  if (1 != 0 && true) {} // LINT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

void bad() {
  if (1 < 0 && true) {} // LINT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

void bad() {
  if (true && false) {} // LINT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

void bad() {
  if (1 != 0) {} // LINT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

void bad() {
  if (true && 1 != 0 || 3 < 4) {} // LINT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

void bad() {
  if (1 != 0 || 3 < 4 && true) {} // LINT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

ПРИМЕЧАНИЕ: Исключение сделано для оператора while (true) { }, который предпочтительнее его эквивалента (;;).

Правильное использование:

void good() {
  while (true) {
    // Do stuff.
  }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

нет_прилегающих_строк_в_списке

Не используйте смежные строки в списке.

Правильное использование:

List<String> list = <String>[
  'a' +
  'b',
  'c',
];
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

List<String> list = <String>[
  'a'
  'b',
  'c',
];
Войдите в полноэкранный режим Выход из полноэкранного режима

нет_дублирования_случайных_значений

Не используйте более одного регистра с одним и тем же значением.

Обычно это опечатка или измененное значение константы.

Правильное использование

const int A = 1;
switch (v) {
  case A:
  case 2:
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

const int A = 1;
switch (v) {
  case 1:
  case 2:
  case A:
  case 2:
}
Войдите в полноэкранный режим Выход из полноэкранного режима

no_logic_in_create_state

Не вкладывайте никакой логики в "createState".

Реализации createState() должны возвращать новый экземпляр объекта state и ничего более. Также следует избегать передачи данных объектам состояния с помощью специальных параметров конструктора, так как доступ к состоянию через область виджета предпочтительнее, и никакие аргументы не должны передаваться конструктору состояния.

Неправильное использование

MyState global;

class MyStateful extends StatefulWidget {
  @override
  MyState createState() {
    global = MyState();
    return global;
  } 
}
Войдите в полноэкранный режим Выход из полноэкранного режима
class MyStateful extends StatefulWidget {
  @override
  MyState createState() => MyState()..field = 42;
}
Войдите в полноэкранный режим Выход из полноэкранного режима
class MyStateful extends StatefulWidget {
  @override
  MyState createState() => MyState(42);
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

class MyStateful extends StatefulWidget {
  @override
  MyState createState() {
    return MyState();
  }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

предпочтительные_относительные_импорты

Для файлов в каталоге /lib/ предпочтите относительный импорт.

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

Правильное использование: import 'bar.dart';

Неправильное использование: import 'package:my_package/bar.dart';

prefer_void_to_null

Не используйте тип Null там, где подойдет Void.

Неправильное использование:

Null f() {}
Future<Null> f() {}
Stream<Null> f() {}
f(Null x) {}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void f() {}
Future<void> f() {}
Stream<void> f() {}
f(void x) {}
Войдите в полноэкранный режим Выход из полноэкранного режима

Некоторые исключения включают формулировку специальных типов функций

Null Function(Null, Null);

и создавать пустые литералы, которые безопасно передавать в места, доступные только для чтения, для любого типа map или list:

<Null>[];
<int, Null>{};
Войдите в полноэкранный режим Выход из полноэкранного режима

тест_типов_в_равных

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

Правильное использование

class Field {
}

class Good {
  final Field someField;

  Good(this.someField);

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) {
      return true;
    }
    return other is Good &&
        this.someField == other.someField;
  }

  @override
  int get hashCode {
    return someField.hashCode;
  }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

class Field {
}

class Bad {
  final Field someField;

  Bad(this.someField);

  @override
  bool operator ==(Object other) {
    Bad otherBad = other as Bad; // LINT
    bool areEqual = otherBad != null && otherBad.someField == someField;
    return areEqual;
  }

  @override
  int get hashCode {
    return someField.hashCode;
  }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

throw_in_finally

Избегайте выброса исключений в последних блоках.

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

Правильное использование:

class Ok {
  double compliantMethod() {
    var i = 5;
    try {
      i = 1 / 0;
    } catch (e) {
      print(e); // OK
    }
    return i;
  }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

class BadThrow {
  double nonCompliantMethod() {
    try {
      print('hello world! ${1 / 0}');
    } catch (e) {
      print(e);
    } finally {
      throw 'Find the hidden error :P'; // LINT
    }
  }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

ненужные_заявления

Избегайте использования ненужных фраз.

Фразы, которые не имеют четкого эффекта, часто бывают лишними или должны быть прерваны.

Например,

Неправильное использование

myvar;
list.clear;
1 + 2;
methodOne() + methodTwo();
foo ? bar : baz;
Войдите в полноэкранный режим Выход из полноэкранного режима

Подобные коды показывают неполноту мышления и являются ошибкой.

Правильное использование:

some.method();
const SomeClass();
methodOne();
methodTwo();
foo ? bar() : baz();
return myvar;
Войдите в полноэкранный режим Выход из полноэкранного режима

несвязанные_типы_равенства_чеков

Не используйте оператор равенства при сравнении ссылок на несвязанные типы.

Сравнение ссылок на тип, где ни один из них не является подтипом другого, скорее всего, вернет false и может не отражать замысел программиста.

Int64 и Int32 в package:fixnum позволяют сравнивать с int, если int2 находится в правой части. Lint допускает это как особый случай.

Неправильное использование:

void someFunction() {
  var x = '1';
  if (x == 1) print('someFunction'); // LINT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

void someFunction1() {
  String x = '1';
  if (x == 1) print('someFunction1'); // LINT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

void someFunction13(DerivedClass2 instance) {
  var other = DerivedClass3();

  if (other == instance) print('someFunction13'); // LINT
}

class ClassBase {}

class DerivedClass1 extends ClassBase {}

abstract class Mixin {}

class DerivedClass2 extends ClassBase with Mixin {}

class DerivedClass3 extends ClassBase implements Mixin {}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void someFunction2() {
  var x = '1';
  var y = '2';
  if (x == y) print(someFunction2); // OK
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void someFunction3() {
  for (var i = 0; i < 10; i++) {
    if (i == 0) print(someFunction3); // OK
  }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void someFunction4() {
  var x = '1';
  if (x == null) print(someFunction4); // OK
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void someFunction7() {
  List someList;

  if (someList.length == 0) print('someFunction7'); // OK
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void someFunction8(ClassBase instance) {
  DerivedClass1 other;

  if (other == instance) print('someFunction8'); // OK
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void someFunction10(unknown) {
  var what = unknown - 1;
  for (var index = 0; index < unknown; index++) {
    if (what == index) print('someFunction10'); // OK
  }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

void someFunction11(Mixin instance) {
  var other = DerivedClass2();

  if (other == instance) print('someFunction11'); // OK
  if (other != instance) print('!someFunction11'); // OK
}

class ClassBase {}

abstract class Mixin {}

class DerivedClass2 extends ClassBase with Mixin {}
Войдите в полноэкранный режим Выход из полноэкранного режима

unsafe_html

Избегайте небезопасных API HTML.

- Прямое присвоение полю href элемента AnchorElement
- Прямое присвоение полю src элемента EmbedElement, IFrameElement, ImageElement или ScriptElement
- Прямое присвоение полю srcdoc элемента IFrameElement
- Вызовите метод createFragment элемента Element
- Вызов метода открытия окна
- Вызовите метод setInnerHtml элемента Element
- Вызов конструктора element.html
- Вызов конструктора DocumentFragment.html

Неправильное использование

var script = ScriptElement()..src = 'foo.js';
Войдите в полноэкранный режим Выход из полноэкранного режима

использовать_строительство_контекста_синхронно

Не используйте BuildContexts в асинхронных разрывах.

Хранение BuildContext для последующего использования может привести к сбоям, которые трудно диагностировать. Асинхронные разрывы неявно хранят BuildContext и будут пропущены при написании кода.

При использовании BuildContext из StatefulWidget свойство mounted должно проверяться после асинхронного разрыва.

Правильное использование

void onButtonTapped(BuildContext context) {
  Navigator.of(context).pop();
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Неправильное использование

void onButtonTapped(BuildContext context) async {
  await Future.delayed(const Duration(seconds: 1));
  Navigator.of(context).pop();
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Правильное использование

class _MyWidgetState extends State<MyWidget> {
  ...

  void onButtonTapped() async {
    await Future.delayed(const Duration(seconds: 1));

    if (!mounted) return;
    Navigator.of(context).pop();
  }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

use_key_in_widget_constructors

Используйте ключ в конструкторах виджетов.

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

Неправильное использование:

Правильное использование:

class MyPublicWidget extends StatelessWidget {
  MyPublicWidget({Key? key}) : super(key: key);
}
Войдите в полноэкранный режим Выход из полноэкранного режима

действительные_регексы

Используйте правильный синтаксис регулярного выражения.

Используйте правильный синтаксис регулярных выражений при создании экземпляров регулярных выражений.

Регулярные выражения, созданные с неправильным синтаксисом, вызовут FormatException во время выполнения, поэтому их следует избегать.

Неправильное использование: print(RegExp(r'(').hasMatch('foo()'));

Правильное использование: print(RegExp(r'(').hasMatch('foo()'));

В этой статье мы рассмотрели первую группу правил Linter - правила ошибок. В следующей статье мы рассмотрим правила стиля.

Ссылки:
https://medium.com/podiihq/setting-up-lint-rules-in-dart-flutter-1ebbed0418a6
https://medium.flutterdevs.com/lint-rules-in-flutter-efbcf05daeb5
https://dart.dev/tools/linter-rules#directives_ordering
https://dart-lang.github.io/linter/lints/
https://sourcelevel.io/blog/what-is-a-linter-and-why-your-team-should-use-it

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *