#flutter #dart #constructor #statefulwidget
Вопрос:
Я создаю виджет с отслеживанием состояния в Flutter, и поэтому требуется, чтобы все аргументы, передаваемые в конструкторе, были окончательными (поскольку виджеты с отслеживанием состояния помечены аннотацией @immutable).
Дело в том, что я хочу иметь два разных конструктора для своего виджета и исключить некоторые элементы виджета с сохранением состояния, в зависимости от используемого конструктора. Я должен подчеркнуть, что я не хочу, чтобы эти аргументы были необязательными, но обязательными.
Например,
class MyWidget extends StatefulWidget {
MyWidget.first({this.firstArgument}};
MyWidget.second({this.secondArgument});
final int firstArgument;
final String secondArgument;
@override
MyWidget createState() => MyWidgetState();
}
Когда я пишу это, я получаю ошибку компилятора, сообщающую мне, что:
Все конечные переменные должны быть инициализированы, но «Первый аргумент» — нет.
То же самое относится и ко второй переменной-члену.
Как я могу преодолеть это?
Я не могу переместить firstArgument
и secondArgument
в состояние MyWidget, так как я хочу, чтобы они были инициализированы в конструкторе(конструкторах), а также потому, что их не следует изменять. Я не могу пометить их как не окончательные, так как тогда я получу предупреждение компилятора, а также нарушу парадигму виджета с отслеживанием состояния.
Есть ли другой подход, который я должен использовать?
Ответ №1:
Дело в том, что я хочу иметь два разных конструктора для своего виджета и исключить некоторые элементы виджета с сохранением состояния, в зависимости от используемого конструктора. Я должен подчеркнуть, что я не хочу, чтобы эти аргументы были необязательными, но обязательными.
Если вы не хотите, чтобы они были необязательными, вам нужно пометить их как обязательные:
MyWidget.first({required this.firstArgument}};
MyWidget.second({required this.secondArgument});
(Если у вас не включена нулевая безопасность, вместо этого вам нужно будет использовать более слабую @required
аннотацию из package:meta
.)
Я понимаю, что вы хотите firstArgument
, чтобы и secondArgument
требовалось для MyWidget.first
и MyWidget.second
соответственно, но они не предназначены для того, чтобы требоваться вместе (то есть должен быть установлен только один).
Это можно исправить, явно инициализировав оба значения в конструкторах:
MyWidget.first({required this.firstArgument}} : secondArgument = null;
MyWidget.second({required this.secondArgument}): firstArgument = null;
Если у вас включена нулевая безопасность, вам также необходимо будет сделать своих участников недействительными:
final int? firstArgument;
final String? secondArgument;
Комментарии:
1. @jamesdiin — спасибо за подробный ответ. Не могли бы вы вкратце объяснить или указать место, где это делается, синтаксис конструктора, который вы предоставили, и его значение?
Ответ №2:
Может быть, заводские конструкторы помогут?
class MyWidget extends StatefulWidget {
MyWidget._({this.firstArgument, this.secondArgument}};
factory MyWidget.first({@required int first})=>MyWidget._(firstArgument: first, );
factory MyWidget.second({@required String second})=>MyWidget._(secondArgument: second, );
final int firstArgument;
final String secondArgument;
@override
MyWidget createState() => MyWidgetState();
}
Таким образом, вы сможете создать этот виджет только с помощью этих конструкторов (поскольку конструктор класса является частным), и при вызове MyWidget.во-первых, значение secondArgument для виджета будет равно null, и то же самое применимо при использовании MyWidget.во-вторых, с помощью firstArgument
Комментарии:
1. Вы также можете использовать конструкторы перенаправления вместо конструкторов
factory
.