【发布时间】:2021-05-20 20:19:59
【问题描述】:
我正在尝试在 Dart 中编写不可变代码。 Dart 并没有真正考虑到不变性,这就是为什么我需要编写大量样板来实现不变性。因此,我对围绕不变性概念构建的 Scala 等语言如何解决这个问题产生了兴趣。
我目前在 Dart 中使用以下类:
class Profile{
List<String> _inSyncBikeIds = []; // private field
String profileName; // public field
Profile(this.profileName); // You should not be able to pass a value to _inSyncBikeIds
void synchronize(String bikeId){
_inSyncBikeIds.add(bikeId);
}
bool isInSync(String bikeId){
return _inSyncBikeIds.contains(bikeId);
}
void reset(){
_inSyncBikeIds = [];
}
}
immutable 中的同一个类:
class Profile{
final List<String> _inSyncBikeIds = []; // private final field
final String profileName; // public final field
factory Profile(String profileName) => Profile._(profileName); // You should not be able to pass a value to _inSyncBikeIds
Profile._(this._inSyncBikeIds, this.profileName); // private contructor
Profile synchronize(String bikeId){
return _copyWith(inSyncBikeIds: _inSyncBikeIds.add(bikeId);
}
bool isInSync(String bikeId) {
return _inSyncBikeIds.contains(bikeId);
}
Profile reset(){
return _copyWith(inSyncBikeIds: []);
}
Profile copyWith({
String profileName,
}) {
return _copyWith(profileName: profileName)
}
Profile _copyWith({
String profileName,
List<Id> inSyncBikeIds,
}) {
return Profile._(
profileName: profileName ?? this.profileName,
inSyncBikeIds: inSyncBikeIds ?? _inSyncBikeIds);
}
}
到目前为止,我从 Scala 了解到的是,对于每个类,都会自动创建一个 copy 方法。为了能够使用copy 方法更改字段,它需要成为构造函数的一部分。
我希望字段 _inSyncBikeIds 为 final(在 Scala 中为 val)。为了更改字段_inSyncBikeIds 的值,我需要创建对象的副本。但是为了使用copy方法,改变字段,它需要是类的构造函数的一部分,比如class Profile(private val _inSyncBikeIds, val profileName)。但这会破坏封装,因为每个人都可以创建一个对象并初始化_inSyncBikeIds。就我而言,_inSyncBikeIds 在初始化后应该始终是一个空列表。
三个问题:
- 如何在 Scala 中解决这个问题?
- 当我在类内部使用
copy方法时,可以使用copy方法更改私有字段吗? - Scala 中的
copy方法是否也复制私有字段(即使它们不是构造函数的一部分,当然也不能改变该私有字段)?
【问题讨论】:
-
听起来你在这里混淆了很多想法。并非 Scala 中的每个类都得到
copy;只有 case 类 可以免费获得它,并且这些类专门用于您希望 数据公开且不可变的情况。如果您要封装私有数据,您确实不需要案例类。你会使用一个普通的class,你要么不会得到copy,要么你会手动实现它来做任何有意义的事情。 -
@SilvioMayolo 谢谢!我明白,所以即使在 Scala 中,我也需要编写自己的复制方法,以实现所有类的真正不变性:(
-
您希望该字段是不可变的,并且“初始化为空”。这意味着它永远是空的(你不能改变它,因为它是不可变的),不是吗?
-
我希望能够制作对象的副本,并将字符串添加到列表中。类似于
synchronize方法。 -
你不能在 dart 中有一个私有构造函数吗?如果它是一个东西,这似乎是一个明显的解决方案,不是吗?
标签: scala immutability