2017-12-02 361 views
1

下鑄造的類型類Scala中

trait OptionTransaction { 
    def data: Data 
} 

BuyOptionTransaction extends OptionTransaction 
SellOptionTransaction extends OptionTransaction 

我使用這些有格式類型的類來創建各種交易

trait Formatter[T] { 
    def format(ot:T):String 
} 

object Formatter { 
    def apply[T](implicit screen: Formatter[T]) = screen 

    implicit val buyOT = new Formatter[BuyOptionTransaction] { 
    def format(ot: BuyOptionTransaction):String = ot.x.toString 
    } 

    implicit val sellOT = new Formatter[SellOptionTransaction] { 
    def format(ot: SellOptionTransaction):String = ot.y.toString 
    } 
} 

的字符串表示這是切入點:

import Formatter._ 
val closeTransactions: List[OptionTransaction] = ... 
closeTransactions.map(startFormat) 

問題closeTransactions有類型List[OptionTransaction]和類型類需要OptionTransaction downcast到BuyOptionTransactionSellOptionTransaction否則它將不會找到隱式格式化程序。

我該如何自動實現這種下降?

+0

您可以更改'OptionTransaction'及其派生類的定義嗎?通常情況下,可以將抽象的'format'添加到'OptionTransaction'並在派生類中根據需要實現它,從而獲得非常簡單和高效的解決方案。 – Suma

+0

如果我對我很熟悉......我想我已經回答了一個類似的問題,以便可以將其標記爲重複:[通過隱式證據獲取運行時類型](https://stackoverflow.com/questions/ 42292338/get-runtime-type-by-implicit-evidence/42293934#42293934) – Suma

回答

1

可以collect相應類型:

val closeTransactions: List[OptionTransaction] = ??? 
val buys = closeTransactions.collect { case b: BuyOptionTransaction => b} 
val sells = closeTransactions.collect { case s: SellOptionTransaction => s} 

現在你可以應用適當的類型類。

將動作/轉換添加到OptionTransaction特徵並將其用於動態綁定可能會更好。如果您想繼續爲其中一個人工作,請查看this answer

+0

是的,我知道收集,但它涉及到我做'手工'鑄造。必須有另一種方式。除了我在示例代碼中展示的兩種以上的交易外,我會檢查出其他答案。 – Adrian

+1

在這種情況下,我會建議製作基本特徵('OptionTransaction')'sealed'並檢查[Shapeless'coproducts](https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0。 0#coproducts-and-discriminated-union)來生成通用實現。 –

+0

我想我可能會去coproduct的方式 – Adrian

2

如果您想要處理多態運行時,您需要實現某種動態(運行時)調度,而不是類型類,它們是靜態的(編譯時)。它可能看起來像這樣:

type Data = String 
trait OptionTransaction { 
    def data: Data = "" 
} 

class BuyOptionTransaction extends OptionTransaction { 
    def x: String = "X" 
} 
class SellOptionTransaction extends OptionTransaction { 
    def y: String = "Y" 

} 

trait Formatter[T] { 
    def format(ot:T):String 
} 

object Formatter { 
    def apply[T](implicit screen: Formatter[T]) = screen 

    def selectFormatter[T](obj: T)(implicit formatter: Formatter[T]) = formatter 

    implicit val buyOT = new Formatter[BuyOptionTransaction] { 
    def format(ot: BuyOptionTransaction):String = ot.x.toString 
    } 

    implicit val sellOT = new Formatter[SellOptionTransaction] { 
    def format(ot: SellOptionTransaction):String = ot.y.toString 
    } 

    implicit val ot = new Formatter[OptionTransaction] { 
    def format(ot: OptionTransaction):String = ot match { 
     case ot: BuyOptionTransaction => 
     selectFormatter(ot).format(ot) 
     case ot: SellOptionTransaction => 
     selectFormatter(ot).format(ot) 
    } 
    } 
} 

def startFormat[T](ot: T)(implicit ev: Formatter[T]) = { 
    ev.format(ot) 
} 
import Formatter._ 

val closeTransactions: List[OptionTransaction] = List(new BuyOptionTransaction, new SellOptionTransaction) 

closeTransactions.map(startFormat(_))