2016-09-20 267 views
0

我正在嘗試使用Scala的一些泛型編程,並試圖找出如何創建如下代碼中所述的類型爲CC的類的實例。我曾經爲了逼誰希望創建自己的特殊OrderBook類使用定義的接口用戶自定義以下的抽象特質......在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 

} 

...然後這種特質在同伴對象的隱藏實現在特質而不是具體實現的子類中。這裏是同伴對象...

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! 
    } 

} 

我想弄清楚如何在我的執行MutableOrderBook創建CC類型的空實例。我希望這可以在沒有反思的情況下完成。如果需要反思,我會接受有關如何避免在此用例中使用反思的建議。思考?

+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的集合庫使用CanBuildFrom很多內部,例如打造mapflatMap權集合。欲瞭解更多信息,請閱讀this的答案。

+0

我正在嘗試實施您的解決方案。但似乎無法獲得編譯的代碼。如果我理解正確,在這種情況下'Elem'類型應該是'(UUID,O)'。但是,從「From」類型使用什麼?我是否需要創建自己的定製'CanBuildFrom'或者我應該能夠使用已經在作用域中隱式定義的一個?我認爲應該已經有一個隱含的範圍,用於在任何元素集合(UUID,O)之外構建一個'mutable.Map [UUID,O]子類型的子類型。 – davidrpugh

+0

我們不關心'To'和'From',所以我什麼也沒用。由於相反,CanBuildFrom與CC作爲'To'是CanBuildFrom的一個子類型[Nothing,Nothing,CC],並將滿足我們的需求。換句話說,我們不關心它可以構建什麼樣的元素,因爲我們實際上不需要向構建器添加任何東西。你會得到什麼錯誤? –

+0

我得到了錯誤,說編譯器不知道如何用'Nothing'中的'Nothing'元素來構建'CC'類型的集合。 – davidrpugh