2016-09-19 66 views
0

在之前的SO post中,我问到了一种惯用的方法来使一个容器类包装一个线程安全的不可变集合。我收到的所有涉及使用各种风格的读/写锁或同步的答案不是我想要的。如何让一个类包装一个不可变的集合在Scala中不可变?

让我问一个不同的问题。我如何让以下类包装一个不可变的容器?该方法add/remove需要返回一个新MyContainer类实例适当改变,但我不能完全看怎么办呢?

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在构造函数)。更多的想法?

+0

以'backingStore'开始''val'而不是'@volatile var',并且看到哪里会导致......(编辑:错字) –

+0

为了使'backingStore'本身是私人的(但不是构造函数),你可以删除'val'(或者显式地写'private val')。 –

回答

1

您需要一种方法来构建一个新的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] = [email protected] 

这真的取决于你想要在API中公开,但是。我不确定你要用filter去干什么,所以我把它从我的例子中删除了。

+0

有趣!不知道私人构造函数。为了证明我正在封装底层的不可变集合以便仅向用户公开其功能的一个子集,我包含了'filter'。为了保证线程安全,我有兴趣保持不变性。 – davidrpugh

相关问题