2016-09-20 12 views
0

저는 스칼라로 제네릭 프로그래밍을하고 싶습니다. 아래 코드에서 설명한대로 CC 클래스의 인스턴스를 만드는 방법을 알아 내려고 노력하고 있습니다. 나는 정의 된 인터페이스를 사용하는 자신 만의 특별한 OrderBook 클래스를 생성하고자하는 사용자를 강제하기 위해 다음 동반자 개체에서이 특성의 숨겨진 구현을 ...스칼라에서 제네릭 형식의 인스턴스를 만드시겠습니까?

/** 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 

} 

을 다음과 같은 추상적 인 특성을 정의 ... 그리고 한 특성에서 구체적인 구현에서 하위 클래스로 분류하기보다는. 여기에 동반자 개체 ... 내가 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 
} 

스칼라 컬렉션 라이브러리를 사용 CanBuildFrom 많은 내부적 mapflatMap에 올바른 수집을 구축하기 위해, 예를 들어. 자세한 내용은 this 답을 읽으십시오.

+0

당신의 솔루션을 구현하려고합니다. 그러나 컴파일 할 코드를 얻지 못하는 것 같습니다. 내가 정확하게 이해한다면이 경우에'Elem' 유형은'(UUID, O)'이어야합니다. 하지만 'From'유형에 사용할 것은 무엇입니까? 나 자신 만의 맞춤형 CanBuildFrom을 생성해야합니까, 아니면 이미 내재적으로 범위에 정의 된 것을 사용할 수 있어야합니까? UUID, O의 어떤 집합에서든'mutable.Map [UUID, O]'의 하위 유형을 작성하기위한 범위가 이미 암시되어야한다고 생각합니다. – davidrpugh

+0

우리는'To '와'From'에 관심이 없기 때문에 아무것도 사용하지 않았습니다. contravariance 때문에 CC를 가진 To를 가진 CanBuildFrom은 CanBuild [Nothing, Nothing, CC]의 하위 타입이며 우리의 필요에 부합 할 것입니다. 즉 빌더에 아무 것도 추가 할 필요가 없으므로 빌드 할 수있는 요소의 종류는 중요하지 않습니다. 어떤 오류가 발생합니까? –

+0

나는 컴파일러가'Nothing'에서'Nothing'의 요소를 가진'CC' 타입의 콜렉션을 빌드하는 법을 모른다는 것을 알게되고 에러가 난다. – davidrpugh