#constructor #properties #dart #flutter #spread-syntax
#constructor #свойства #dart #трепетание #распространение-синтаксис
Вопрос:
В моем приложении flutter у меня есть виджеты, подобные приведенным ниже:
Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.red,
width: 2,
style: BorderStyle.solid,
),
),
child: Text('Container 1'),
)
Container(
decoration: BoxDecoration(
border: Border(
top: BorderSide(
color: Colors.red,
width: 2,
style: BorderStyle.solid,
),
),
),
child: Text('Container 2'),
)
Оба используют одни и те же свойства для своих границ. Итак, мне было интересно, существует ли способ, подобныйоператору распространения, для вставки одинаковых свойств для обоих виджетов? Может быть, как:
const borderBase = (
color: Colors.red,
width: 2,
style: BorderStyle.solid,
)
Container(
decoration: BoxDecoration(
border: Border.all(
...borderBase,
),
),
child: Text('Container 1'),
)
Container(
decoration: BoxDecoration(
border: Border(
top: BorderSide(
...borderBase,
),
),
),
child: Text('Container 2'),
)
Ответ №1:
Такого понятия не существует.
Оператор распространения находится в разработке, но он предназначен только для списков, а не классов (https://github.com/dart-lang/language/issues/47 )
Комментарии:
1. Я понимаю. То есть нет способа повторно использовать те же свойства динамически? Означает, что я должен повторять их каждый раз?
2. Да, вы вынуждены. Но вы можете обсудить это по этому вопросу. Я думаю, что это тоже интересная функция.
3. 2022 — zzzzzzzzzzzzzz
Ответ №2:
Теперь, когда в dart есть как оператор распространения, так и расширения класса, вы можете злоупотреблять обоими, чтобы добавить ...spread
поддержку static
методов. Хотя я сомневаюсь, что это хорошая идея, я создал работающий dartpad (суть) для демонстрации. Конечный результат выглядит примерно так:
final Border spreadBorder = Border.fromSides([
...Border(
left: BorderSide(color: Colors.pink),
right: BorderSide(color: Colors.pinkAccent),
).sides,
...Border(
top: BorderSide(color: Colors.blue),
bottom: BorderSide(color: Colors.blueAccent),
).sides,
]).scale(5);
enum _Side { top, right, bottom, left }
extension SpreadBorder on Border {
Iterable<MapEntry<_Side, BorderSide>> get sides {
return () sync* {
if (top != BorderSide.none) {
yield MapEntry(_Side.top, top);
}
// ...other yields
}();
}
static Border fromSides(Iterable<MapEntry<_Side, BorderSide>> parts) {
BorderSide top, right, bottom, left;
for (final borderPart in parts) {
switch (borderPart.key) {
case _Side.top:
top = borderPart.value;
break;
// ... other cases
}
}
return Border(
top: top,
right: right,
bottom: bottom,
left: left,
);
}
}
Ответ №3:
Вы можете сделать что-то вроде этого:
const BorderSide borderBase = BorderSide(
color: Colors.red,
width: 2,
style: BorderStyle.solid,
);
Container(
decoration: BoxDecoration(
border: Border.all(
color: borderBase.color,
width: borderBase.width,
style: borderBase.style,
),
),
child: Text('Container 1'),
)
Container(
decoration: BoxDecoration(
border: Border(
top: borderBase,
),
),
child: Text('Container 2'),
)
Не самый лучший, но все же некоторое повторное использование.
Комментарии:
1. Но таким образом я получаю ошибки в
borderBase
переменной sayingUndefined name 'color'
и другие ошибки linter .2.О, я думаю, вы имели в виду, что
borderBase
var должен использоватьBorderSide()
класс, верно? Потому что это, кажется, работает.
Ответ №4:
Вот фиктивный образец шаблона оператора распространения моего бедняги:
Я создаю конструктор копирования для классов, часто создаваемых заново с небольшими изменениями. Это дополнительная работа во время определения, но она окупается во многих местах при использовании этих классов. Тот же шаблон можно использовать в стандартных классах путем создания подклассов — просто для подключения к конкретному вопросу.
class Address {
final String street;
final String city;
final String state;
Address({this.street, this.city, this.state});
Address.copy(Address copy, {
String street,
String city,
String state,
}) : this (
street: street ?? copy.street,
city: city ?? copy.city,
state: state ?? copy.state,
);
}
class User {
final String firstName;
final String lastName;
final Address address;
final String email;
User({this.firstName, this.lastName, this.address, this.email});
User.copy(User copy, {
String firstName,
String lastName,
Address address,
String email,
}) : this (
firstName: firstName ?? copy.firstName,
lastName: lastName ?? copy.lastName,
address: address ?? copy.address,
email: email ?? copy.email,
);
}
void workWithUsers(User user) {
final userChangedEmail = User.copy(user, email: 'new@email.com');
final userMovedToAnotherStreet = User.copy(user, address: Address.copy(user.address, street: 'Newstreet'));
}
Ответ №5:
Оператор распространения будет работать с картами, например, Map<String, dynamic>
поэтому у меня получилось преобразовать объект в json, который является Map<String, dynamic>
, использовать оператор распространения, а затем преобразовать обратно в объект.
Вы можете попробовать что-то вроде этого:
class Something {
final String id;
final String name;
Something({required this.id, required this.name});
factory Something.fromJson(Map<String, dynamic?> json){
return Something(
id: json['id'],
name: json['name']
);
}
Map<String, dynamic?> toJson() {
return {
'id': id,
'name': name
};
}
}
final x = Something(id: 'abc', name: 'def');
final y = Something.fromJson({...x.toJson(), 'name': 'somethingElse'})
Это может быть очень дорого, но если все, что вас волнует, это использование оператора распространения, это должно выполнить свою работу.