2016-09-19 7 views
0

先ほど、SO postで、スレッドセーフで不変なコレクションをラップするコンテナクラスを作成するための慣用方法について質問しました。私が受け取った回答は、私が望むものではない様々な読み書きロックや同期を使っていました。不変のコレクションをScalaでラップしないようにするには?

私は別の質問をします。不変のコンテナをラップする次のクラスを不変にするにはどうすればよいですか? ...

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] 

} 

思考方法はadd/remove適宜変更新しいMyContainerクラスのインスタンスを返す必要があるが、私は非常にそれを行う方法を見ることができませんか?

EDIT:コメントに反応しては、一つの可能​​な解決策は

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'を' @volatile var'ではなく 'val'にして、それがどこから来るのかを見てみましょう。(編集:typo) –

+0

' backingStore'自体を非公開にします'val'を単に削除する(または明示的に' private val'を書く)ことができます。興味深い! –

答えて

1

すでにいくつかの要素が含まれており、好ましくは同じUUIDを維持する新しいMyContainerを構築する方法が必要です。つまり、基本的には初期化するコンストラクタが必要です。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

関連する問題