最初为空的不可空容器或最初可为空且为空的容器哪个更好?

What's better, an initially empty non-nullable or an initially nullable and null container?

假设您正在管理建筑物内居民拥有的自行车的序列号列表,并objective提前计划建造额外的安全自行车存放处。

有些人当然没有自行车。

在 Dart > 2.12 中(null safety)你可以 使用不可为 null 的 List<String> 并将其初始化为空列表

class Resident {
  String name;
  List<String> bicycles = [];
}

或者您可以使用可为 null 的 List<String> 并使用 null 作为标志来表示某人没有自行车。

class Resident {
  String name;
  List<String>? bicycles;
}

这两种设计当然都是可行的,但在未来是否会发现一个明显优于另一个——例如,更符合新 Dart 的习惯?换句话说,最初为空的不可空容器或最初可为空且为空的容器哪个更好?

即使我计算所需的位数,也不是很清楚。在第一种情况下会浪费存储空间来构建一个空列表,但在第二种情况下也会浪费存储空间——尽管它是未知的,并且可能依赖于实现——数量。

如果您想表示拥有 none 某物,则优先使用具有空状态的不可空容器类型而不是可空类型。

  • 对于可为 null 的容器,您可能需要处理容器为空的情况,现在您必须做额外的工作来检查所有地方的 null。 同时,处理空容器通常不需要任何额外工作。对比:
    // Nullable case.
    final bicycles = resident.bicycles;
    if (bicycles != null) {
      for (var bicycle in bicycles) {
        doSomething(bicycle);
      }
    }
    
    /// Non-nullable case.
    for (var bicycle in resident.bicycles) {
      doSomething(bicycle);
    }
    
  • 您可以尝试在容器变空时重置对 null 的引用,这样就没有两种情况需要处理,但如上所述,空情况通常是免费的,所以'做更多的工作通常是没有收获的。此外,重置引用可能需要 很多 的额外工作:
    var list = [1, 2, 3];
    mutateList(list);
    if (list.isEmpty) {
      list = null;
    }
    
    如果 mutateList 可以从 list 中删除元素,那么 每个 调用者都需要做额外的工作来将空的 List 替换为 null .
  • 即使您不关心用 null 替换空容器,在转换到非空容器时您仍然会有不同的行为。考虑:
    var sam = Resident();
    var samsBicycles = sam.bicycles;
    sam.addBicycle();
    
    您希望 samsBicycles 是什么?如果 Resident.bicycles 最初是 null,那么 samsBicycles 将保持 null 并且不再引用与 sam.bicycles.
  • 相同的对象