【问题标题】:Dart - How to extend Map with a specific constructor?Dart - 如何使用特定的构造函数扩展 Map?
【发布时间】:2020-06-04 11:04:23
【问题描述】:

我想使用数据库表的抽象类扩展 Darts 映射,然后必须为每个表扩展(参见下面的完整示例)。抽象类有一个构造函数,它已经设置了一些条目,但没有显式调用其超类中的任何构造函数。

问题是创建子类并直接设置条目(如map允许)。

我已尝试正确遵循此answer

import 'package:uuid/uuid.dart';

void main(List<String> args) {
  Map<String, dynamic> map = {
    'key': 99,
  };
  SomeTable one = SomeTable();
  print('$one with ${one.length} entries -> ${one.prettyPrint()}');
  SomeTable another = SomeTable();
  one['child'] = another;
  print('$one with ${one.length} entries -> ${one.prettyPrint()}');
  SomeTable third = {
    'key': 17,
  };
}

class SomeTable extends TableMap {
  SomeTable() : super('sometable');
  void someSpecificFunction() {}
}

abstract class TableMap implements Map<String, dynamic> {
  final Map _inner = <String, dynamic>{};

  static const String id = 'id', // 64bit
      uuid = 'uuid',
      identifier = 'identifier', // String "$tablename:$id"
      tablename = 'tablename';

  /// Constructor
  TableMap(String _tablename) {
    String uuidAsString = Uuid().v4();
    _inner[uuid] = uuidAsString;
    _inner[identifier] = tablename + ':' + uuidAsString;
    _inner[tablename] = _tablename;
  }

  /// Returns `true` if `ìd` = `null`
  bool get isNew => ([id] == null) ? true : false;

  @override
  operator [](Object key) {
    return _inner[key];
  }

  @override
  void operator []=(String key, value) {
    _inner[key] = value;
  }

  @override
  void addAll(Map<String, dynamic> other) {
    _inner.addAll(other);
  }

  @override
  void addEntries(Iterable<MapEntry<String, dynamic>> newEntries) {
    _inner.addEntries(newEntries);
  }

  @override
  Map<RK, RV> cast<RK, RV>() {
    return _inner.cast<RK, RV>();
  }

  @override
  void clear() {
    _inner.clear();
  }

  @override
  bool containsKey(Object key) {
    return _inner.containsKey(key);
  }

  @override
  bool containsValue(Object value) {
    return _inner.containsValue(value);
  }

  @override
  Iterable<MapEntry<String, dynamic>> get entries => _inner.entries;

  @override
  void forEach(void Function(String key, dynamic value) f) {
    _inner.forEach(f);
  }

  @override
  bool get isEmpty => _inner.isEmpty;

  @override
  bool get isNotEmpty => _inner.isNotEmpty;

  @override
  Iterable<String> get keys => _inner.keys;

  @override
  int get length => _inner.length;

  @override
  Map<K2, V2> map<K2, V2>(
      MapEntry<K2, V2> Function(String key, dynamic value) f) {
    return _inner.map(f);
  }

  @override
  putIfAbsent(String key, Function() ifAbsent) {
    return _inner.putIfAbsent(key, ifAbsent);
  }

  @override
  remove(Object key) {
    return _inner.remove(key);
  }

  @override
  void removeWhere(bool Function(String key, dynamic value) predicate) {
    _inner.removeWhere(predicate);
  }

  @override
  update(String key, Function(dynamic value) update, {Function() ifAbsent}) {
    return _inner.update(key, update, ifAbsent: ifAbsent);
  }

  @override
  void updateAll(Function(String key, dynamic value) update) {
    _inner.updateAll(update);
  }

  @override
  Iterable get values => _inner.values;

  /// Creates a string by putting each entry on a separate line and
  /// prefixing it with spaces according to its depth within the map.
  String prettyPrint() {
    return _prettyPrintMap(this, 0);
  }

  static final String _spaces = '                                   ';

  String _prettyPrintList(List<dynamic> list, int depth) {
    depth++;
    String _indent = _spaces.substring(0, 2 * depth);
    String out = '[\n';
    list.forEach((element) {
      out = out + _indent;
      print('_printList( element=$element is ${element.runtimeType}');
      if (element is Map) {
        out = out + _prettyPrintMap(element, depth) + ',\n';
      } else if (element is List) {
        out = out + _prettyPrintList(element, depth) + ',\n';
      } else {
        out = out + element.toString() + ',\n';
      }
    });
    depth--;
    return out + ']';
  }

  String _prettyPrintMap(Map<dynamic, dynamic> map, int depth) {
    depth++;
    String _indent = _spaces.substring(0, 2 * depth);
    String out = '{\n';
    map.forEach((k, v) {
      out = out + _indent + k + ': ';
      if (v is Map) {
        out = out + _prettyPrintMap(v, depth) + ',\n';
      } else if (v is List) {
        out = out + _prettyPrintList(v, depth);
      } else {
        out = out + v.toString() + ',\n';
      }
    });
    depth--;
    return out + '}';
  }
}

【问题讨论】:

    标签: inheritance dart


    【解决方案1】:

    你的TableMap 类不是extend Map,它是implements。因此,您不要调用 Map 的构造函数 - 这似乎是正确的方法。

    如果你想在构造时填充你的数据持有Map _inner,你可以在你的构造函数中这样做;你现在的做法看起来不错,或者你可以在构造函数中完全初始化你的变量。

    当然,您不能只为自定义实现使用文字语法 - 文字基本上绑定到默认的 Map。但是您可以添加一个构造函数,该构造函数接受一些值并将这些值传递给您的私有基类构造函数,然后将值添加到 _inner 上。

    例如,您可以添加(类似于Map 接口):

    factory SomeTable.fromEntries(Iterable<MapEntry> entries) {
      final table = SomeTable();
      table._inner.addEntries(entries);
    }
    

    然后使用它:

    SomeTable third = SomeTable.fromEntries({
      'key': 17,
    });
    

    同样,您可以将MapIterable 添加到TableMap 类的现有或新构造函数中,并在构造过程中传递数据。

    【讨论】:

    • 感谢您查看问题。不幸的是,第 12-14 行不起作用。我无法用任何构造函数填充数据。能否提供一个代码示例?
    • 请查看添加的示例。当然,有很多方法可以做到这一点。但我想你不能简单地单独使用花括号。
    猜你喜欢
    • 1970-01-01
    • 2013-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-09
    • 2021-02-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多