Dart:构造函数的扩展运算符

Dart: spread operator for constructor

在我的 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'),
)

它们的边框都使用相同的属性。所以我想知道是否有一种 spread-operator-like 方法可以为两个小部件插入相同的属性?也许喜欢:

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'),
)

没有这样的东西。

展开运算符正在开发中,但它仅适用于列表,不适用于 类 (https://github.com/dart-lang/language/issues/47)

你可以这样做:

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'),
)

不是最好的,但仍有一些重用。

这是我可怜的传播运算符模式的虚拟样本:

我为 类 创建了一个复制构造函数,经常在稍作修改后重新创建。 在定义期间这是额外的工作,但在使用这些 类 时在许多地方都会得到回报。通过子类化,可以在标准 类 上使用相同的模式——只是为了连接到特定问题。

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'));
}

现在 dart 有扩展运算符和 class extensions, you could abuse both to add ...spread support to static methods. While I doubt this is a good idea, I made a working dartpad (gist) 来演示。最终结果类似于:

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,
    );
  }
}

传播运算符将适用于地图,例如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'})

这可能会非常昂贵,但如果您只关心使用展开运算符,那么这应该可以完成。