2014-12-31 9 views
1

나는 경로 의존형을 실험하고있다. 내 간단한 예제에서는 Money 개체를 사용하여 동일한 통화의 Money에서만 Money 계산을 수행 할 수 있습니다.런타임에 경로 종속 유형과 해당 부모 간의 링크를 다시 설정 하시겠습니까?

// Simple currency class 
case class Currency(code: String, name: String, symbol: String) { 

    // Money amounts in this currency 
    // Operations are only supported on money of the same currency 
    case class Money(amount: BigDecimal) { 
    override def toString: String = s"$code $amount" 

    val currency: Currency.this.type = Currency.this 

    def +(rhs: Money): Money = Money(amount + rhs.amount) 

    def -(rhs: Money): Money = Money(amount - rhs.amount) 
    } 
} 

위의 클래스를 사용하면 repl의 간단한 계산은 straigh forward입니다.

val e1 = Euro.Money(5) 
val e2 = Euro.Money(9) 
e1 + e2 // Compiles fine 

val d1 = Dollar.Money(6) 
d1 + e2 // Doesn't compile as expected 

컴파일러가 e1과 e2가 공통 통화를 공유하고 있음을 쉽게 증명할 수 있기 때문에 이는 간단합니다. 그러나 파일이나 데이터베이스에서 금액 금액을 읽을 때 돈 인스턴스가 공통 통화를 공유한다는 사실을 증명하는 것이 훨씬 어렵습니다. 예를 들어 아래의 콜레이트 함수를 구현하는 방법을 볼 수 없습니다.

trait CurrencyAndMonies { 
    val currency: Currency 
    val monies: List[currency.Money] 
} 

// Take a list of money in different currencies and group them by currency 
// so their shared Currency type is available to static type checking 
// in further calculations 
def collate(Seq[Currency#Money]): List[CurrencyAndMonies] = ??? 

통화를 기준으로 돈을 정렬하고 이들 사이의 링크를 재설정 할 수 있습니까? 그리고 만약 그렇다면 어떻게? 서명이나 돈 금액을 데이터베이스에서 읽는 방법을 변경하는 데는 신경 쓰지 않아도됩니다. 당신은 낙심 할 수

답변

1

: Money#currency에 의해

new CurrencyAndMonies { 
    val currency = foo 
    val monies = bars.map(_.asInstanceOf[currency.Money]) 
} 

그룹.

다운 캐스트는 런타임에 확인되지 않으므로 통화 값이 올바른 통화 (통화별로 그룹화하여 이미 수행 한 통화)인지 확인해야하지만 컴파일됩니다. 동일한 통화에서 보낸 모든 돈을 필요로하지 않는 예를 들어 유형 서명

def collate(Seq[Currency#Money]): List[CurrencyAndMonies] 

에서

+0

답해 주셔서 감사합니다. 나는 당신이 옳다 고 생각합니다. 나는 그것을 던져야 할 것입니다. 그것은 동정입니다. 나는 그 순간에 그것을 캐스팅하는 깔끔한 방법을보고있다. (어쩌면 안전을 위해 패턴 매칭 뒤에 놓는다.) – iain

1

는, 어떤 통화에서 임의로 돈이 될 수 있습니다.

val Euro = Currency("EUR", "Euro", "EUR") 
    val USD = Currency("USD", "Dollar", "$") 

    def collateOld(s: List[Currency#Money]): CurrencyAndMonies = ??? 

    // Compiles successfully -> ERROR 
    collateOld(List(USD.Money(10), Euro.Money(20))) 

일반적으로 통화 및 Money 인스턴스 목록을 전달해야합니다. 예를 들어, 당신은 이런 식으로 수행 할 수 있습니다

abstract class CurrencyAndMonies(val currency: Currency) { 
    type Money 
    def monies: List[Money] 
    } 

    def collate(c: Currency) 
      (m: List[c.Money]): CurrencyAndMonies { type Money = c.Money } = 
    new CurrencyAndMonies(c) { 
     type Money = c.Money 
     val monies = m 
    } 


    collate(Euro)(List(Euro.Money(10), Euro.Money(20))) 

그것은이 CurrencyAndMonies 내부 형 돈을 다시 정의 할 필요가 있다는 이상한, 그러나 단지 currency.Money 작동하지 않는 이유를 이해할 수 없습니다. 생성자를 비공개로 만들고 클래스의 인스턴스를 만드는 방법을 하나만 대조하면 보장 된 유형 안전을 위해 사용해야합니다.

+0

답장을 보내 주셔서 감사합니다. 나는 여러 통화로 돈을 대조 할 수 있기를 원했습니다. 파일에서 파일을 읽을 때 Money 인스턴스와 통화 간의 컴파일 시간 링크가 끊어지기 때문입니다. 이 링크를 다시 설정하면 작업이 다시 안전 해집니다. – iain

+0

aaah, 알았어, 원래 질문을 오해했다. –