Dart: оператор распространения для конструктора

#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 переменной saying Undefined 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'})
  

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