«Где есть правила, там есть закон».
Что такое линтинг?
Линтинг — это процесс проверки исходного кода на наличие программных, стилистических ошибок и неформатированного кода. Он помогает выявить некоторые распространенные и редкие ошибки, допущенные при кодировании, такие как логические ошибки, неиспользуемые переменные, пустые операторы if-else.
Цель линтинга — получить рекомендации в реальном времени по выявлению скрытых ошибок, которые могут улучшить качество кода, или ошибок, которые могут вызвать проблемы при выполнении приложения.
Правила Линтера делятся на 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