2016-09-20 9 views
0

私はScalaで汎用プログラミングを少し試していますが、以下のコードで説明されているように、タイプCCのクラスのインスタンスを作成する方法を理解しようとしています。私は...Scalaでジェネリック型のインスタンスを作成しますか?

/** Trait defining the interface for an `OrderBook`. 
    * 
    * @tparam O type of `Order` stored in the order book. 
    * @tparam CC type of collection used to store `Order` instances. 
    */ 
trait OrderBook[O <: Order, CC <: collection.GenMap[UUID, O]] { 

    /** All `Orders` contained in an `OrderBook` should be for the same `Tradable`. */ 
    def tradable: Tradable 

    /** Add an `Order` to the `OrderBook`. 
    * 
    * @param order the `Order` that should be added to the `OrderBook`. 
    */ 
    def add(order: O): Unit 

    /** Filter the `OrderBook` and return those `Order` instances satisfying the given predicate. 
    * 
    * @param p predicate defining desirable `Order` characteristics. 
    * @return collection of `Order` instances satisfying the given predicate. 
    */ 
    def filter(p: (O) => Boolean): Option[collection.GenIterable[O]] = { 
    val filteredOrders = existingOrders.filter { case (_, order) => p(order) } 
    if (filteredOrders.nonEmpty) Some(filteredOrders.values) else None 
    } 

    /** Find the first `Order` in the `OrderBook` that satisfies the given predicate. 
    * 
    * @param p predicate defining desirable `Order` characteristics. 
    * @return `None` if no `Order` in the `OrderBook` satisfies the predicate; `Some(order)` otherwise. 
    */ 
    def find(p: (O) => Boolean): Option[O] = existingOrders.find { case (_, order) => p(order) } match { 
    case Some((_, order)) => Some(order) 
    case None => None 
    } 

    /** Return the head `Order` of the `OrderBook`. 
    * 
    * @return `None` if the `OrderBook` is empty; `Some(order)` otherwise. 
    */ 
    def headOption: Option[O] = existingOrders.values.headOption 

    /** Remove and return the head `Order` of the `OrderBook`. 
    * 
    * @return `None` if the `OrderBook` is empty; `Some(order)` otherwise. 
    */ 
    def remove(): Option[O] = { 
    headOption match { 
     case Some(order) => remove(order.uuid) 
     case None => None 
    } 
    } 

    /** Remove and return an existing `Order` from the `OrderBook`. 
    * 
    * @param uuid the `UUID` for the order that should be removed from the `OrderBook`. 
    * @return `None` if the `uuid` is not found in the `OrderBook`; `Some(order)` otherwise. 
    */ 
    def remove(uuid: UUID): Option[O] 

    /* Underlying collection of `Order` instances. */ 
    protected def existingOrders: CC 

} 

を以下の抽象的形質を定義し...そして定義されたインタフェースを使用するために独自の特殊なOrderBookのクラスを作成したいユーザーを強制するためにコンパニオンオブジェクト内のこの特性の実装を隠して具体的な実装からサブクラス化するのではなく、その特性上のものです。ここではコンパニオンオブジェクトは、私はMutableOrderBookの私の実装でタイプCCの空のインスタンスを作成する方法を見つけ出すしたいと思います...

object OrderBook { 

    import scala.collection.mutable 
    import scala.collection.parallel 

    def apply[O <: Order, CC <: mutable.Map[UUID, O]](tradable: Tradable): OrderBook[O, CC] = { 
    new MutableOrderBook[O, CC](tradable) 
    } 

    def apply[O <: Order, CC <: parallel.mutable.ParMap[UUID, O]](tradable: Tradable): OrderBook[O, CC] = { 
    new ParallelMutableOrderBook[O, CC](tradable) 
    } 

    private class MutableOrderBook[O <: Order, CC <: mutable.Map[UUID, O]](val tradable: Tradable) 
    extends OrderBook[O, CC] { 

    /** Add an `Order` to the `OrderBook`. 
     * 
     * @param order the `Order` that should be added to the `OrderBook`. 
     */ 
    def add(order: O): Unit = { 
     require(order.tradable == tradable) // can be disabled by compiler? 
     existingOrders(order.uuid) = order 
    } 

    /** Remove and return an existing `Order` from the `OrderBook`. 
     * 
     * @param uuid the `UUID` for the order that should be removed from the `OrderBook`. 
     * @return `None` if the `uuid` is not found in the `OrderBook`; `Some(order)` otherwise. 
     */ 
    def remove(uuid: UUID): Option[O] = existingOrders.remove(uuid) 

    /* Underlying collection of `Order` instances. */ 
    protected val existingOrders: CC = ??? // I want this to be an empty instance of type CC! 

    } 

    private class ParallelMutableOrderBook[O <: Order, CC <: parallel.mutable.ParMap[UUID, O]](val tradable: Tradable) 
    extends OrderBook[O, CC] { 
     /// details omitted for brevity! 
    } 

} 

です。これが反映されずにできることを期待しています。リフレクションが必要な場合は、このユースケースでリフレクションを使用しないようにする方法についての提案を公開します。思考?

+0

オブジェクトの 'CC <:collection.GenMap [UUID、O]]'型と 'CC <:mutable.Map [UUID、O]'の理由は何ですか? – Samar

+0

@samerコンパニオンオブジェクトがファクトリになるように、applyメソッドをオーバーロードします。タイプ境界は、私が過負荷にする予定のものです。私はこれを実証するためにオブジェクトを更新しました... – davidrpugh

答えて

1

scala.collection.generic.CanBuildFrom[-From, -Elem, +To]を使用することができます。これは、この問題の原因となります。

private class MutableOrderBook[O <: Order, CC <: mutable.Map[UUID, O]] 
    (val tradable: Tradable)(implicit cbf: CanBuildFrom[Nothing, Nothing, CC]) { 
    //give me a CanBuildFrom, which can build a CC out of Nothing. 

    ... 

    val existingOrders: CC = cbf().result 
} 

Scalaのコレクションライブラリの使用はmapflatMapで右のコレクションを構築するために、たとえば、内部的に多くのことをCanBuildFrom。詳細については、this答えをお読みください。

+0

あなたのソリューションを実装しようとしています。しかし、コードをコンパイルすることはできないようです。私が正しく理解していれば、この場合の 'Elem'型は'(UUID、O) 'でなければなりません。しかし、 'From'型のために何を使うべきですか?私は独自の特注のCanBuildFromを作成する必要がありますか、またはすでにスコープ内で暗黙的に定義されているものを使用できる必要がありますか?私はすでに要素の集合(UUID、O)の中で 'mutable.Map [UUID、O]'のサブタイプを構築するためのスコープに暗黙のうちにあるはずだと思います。 – davidrpugh

+0

「To」と「From」は気にしないので、何も使用しませんでした。反差異のために、CCを「To」とするCanBuildFromは、CanBuildFrom [Nothing、Nothing、CC]のサブタイプであり、私たちのニーズに合致します。言い換えれば、実際にビルダーに何も追加する必要がないため、ビルドできる要素の種類は気にしません。どのようなエラーが出ますか? –

+0

コンパイラが 'Nothing'の中の' Nothing'の要素を持つ 'CC'型のコレクションを構築する方法をコンパイラが知りません。 – davidrpugh

関連する問題