如何使 class 包装一个在 Scala 中不可变的不可变集合?
How to make a class wrapping an immutable collection immutable in Scala?
在之前的 中,我询问了一种使容器 class 包装线程安全的不可变集合的惯用方法。我收到的所有答案都涉及使用各种风格的 read/write 锁或同步,这不是我想要的。
让我问一个不同的问题。如何使包装不可变容器的以下 class 不可变? add
/remove
方法需要 return 一个新的 MyContainer
class 实例适当地改变,但我不太明白如何去做......
class MyContainer[A] {
// method that returns a new MyContainer that includes the additional thing...
def add(thing: A): MyContainer[A] = {
???
}
def filter(p: A => Boolean): Option[Iterable[A]] = {
val filteredThings = backingStore.values.filter(p)
if (filteredThings.isEmpty) None else Some(filteredThings)
}
// method that returns a new MyContainer that does not include the thing with given uuid
def remove(uuid: UUID): MyContainer[A] = {
???
}
@ volatile private[this] var backingStore = immutable.HashMap.empty[UUID, A]
}
想法?
编辑: 作为对评论的回应,一种可能的解决方案类似于以下...
class MyContainer[A](val backingStore: immutable.HashMap[UUID, A]) {
def add(thing: A): MyContainer[A] = {
new MyContainer(backingStore + (thing.uuid -> thing))
}
def filter(p: A => Boolean): Option[Iterable[A]] = {
val filteredThings = backingStore.values.filter(p)
if (filteredThings.isEmpty) None else Some(filteredThings)
}
def remove(uuid: UUID): MyContainer[A] = {
new MyContainer(backingStore - uuid)
}
}
...backingStore
不再是私有的(但可以将 private
放入构造函数中)。更多想法?
您需要一种方法来构建一个新的 MyContainer
,它已经包含一些元素并且最好保持相同的 UUID。这意味着您基本上需要一个初始化 backingStore
的构造函数。但是,如果您不想以任何方式公开它,您可以将构造函数设为私有,并提供一个仅允许外部代码创建空集合的重载构造函数(假设)。 backingStore
可以简单地移到私有构造函数中。
class MyContainer[A] private (backingStore: HashMap[UUID, A]) {
def this() = this(HashMap.empty[UUID, A])
def add(thing: A): MyContainer[A] = {
val uuid: UUID = UUID.randomUUID() // or however the UUID is generated
new MyContainer(backingStore + ((uuid, thing)))
}
def remove(uuid: UUID): MyContainer[A] =
new MyContainer(backingStore - uuid)
}
scala> val container = new MyContainer[String]()
scala> container.add("a").add("b").add("c")
res2: MyContainer[String] = MyContainer@4a183d02
不过,这完全取决于您是否希望在 API 中公开。我不确定你要用 filter
做什么,所以我把它从我的例子中删除了。
在之前的
让我问一个不同的问题。如何使包装不可变容器的以下 class 不可变? add
/remove
方法需要 return 一个新的 MyContainer
class 实例适当地改变,但我不太明白如何去做......
class MyContainer[A] {
// method that returns a new MyContainer that includes the additional thing...
def add(thing: A): MyContainer[A] = {
???
}
def filter(p: A => Boolean): Option[Iterable[A]] = {
val filteredThings = backingStore.values.filter(p)
if (filteredThings.isEmpty) None else Some(filteredThings)
}
// method that returns a new MyContainer that does not include the thing with given uuid
def remove(uuid: UUID): MyContainer[A] = {
???
}
@ volatile private[this] var backingStore = immutable.HashMap.empty[UUID, A]
}
想法?
编辑: 作为对评论的回应,一种可能的解决方案类似于以下...
class MyContainer[A](val backingStore: immutable.HashMap[UUID, A]) {
def add(thing: A): MyContainer[A] = {
new MyContainer(backingStore + (thing.uuid -> thing))
}
def filter(p: A => Boolean): Option[Iterable[A]] = {
val filteredThings = backingStore.values.filter(p)
if (filteredThings.isEmpty) None else Some(filteredThings)
}
def remove(uuid: UUID): MyContainer[A] = {
new MyContainer(backingStore - uuid)
}
}
...backingStore
不再是私有的(但可以将 private
放入构造函数中)。更多想法?
您需要一种方法来构建一个新的 MyContainer
,它已经包含一些元素并且最好保持相同的 UUID。这意味着您基本上需要一个初始化 backingStore
的构造函数。但是,如果您不想以任何方式公开它,您可以将构造函数设为私有,并提供一个仅允许外部代码创建空集合的重载构造函数(假设)。 backingStore
可以简单地移到私有构造函数中。
class MyContainer[A] private (backingStore: HashMap[UUID, A]) {
def this() = this(HashMap.empty[UUID, A])
def add(thing: A): MyContainer[A] = {
val uuid: UUID = UUID.randomUUID() // or however the UUID is generated
new MyContainer(backingStore + ((uuid, thing)))
}
def remove(uuid: UUID): MyContainer[A] =
new MyContainer(backingStore - uuid)
}
scala> val container = new MyContainer[String]()
scala> container.add("a").add("b").add("c")
res2: MyContainer[String] = MyContainer@4a183d02
不过,这完全取决于您是否希望在 API 中公开。我不确定你要用 filter
做什么,所以我把它从我的例子中删除了。