[英]Pairing type argument and argument sub-type argument in scala
我很難做一個我發現可以以一種聰明的方式解決我的問題的實現:我想對不同的輸出類型有一些“轉換器”的實現,但所有實現都共享一些Schema定義。
用單詞來解釋很難,所以這里有一個示例代碼:
sealed trait Schema[+A]
object Schema{
// Schema definition
object IntSchema extends Schema[Int]
// ...
case class SeqSchema[B](bSchema: Schema[B]) extends Schema[Seq[B]]
// ...
case class MappedSchema[A,B](aToB: A => B, bSchema: Schema[B]) extends Schema[A]
// ...
// base implementations of conversion to "Dst"
trait Dst // some output type, used below
def convertIntToDst(i: Int): Dst = ???
def convertSeqToDst[A](s: Seq[A]): Dst = ???
// ...
// *** here is what I want to do: ***
// combine base conversion using schema
def convertToDst[A](a: A, schema: Schema[A]): Dst = schema match {
case IntSchema =>
convertIntToDst(a.asInstanceOf[Int]) // (1) asInstanceOf :(
case s: SeqSchema[_] =>
convertSeqToDst(a.asInstanceOf[Seq[_]].map{ ai => // (2)
convertToDst(ai, s.bSchema) // (3)
})
case s: MappedSchema[_,_] =>
convertToDst(s.aToB(a), s.bSchema) // (4) fails to compile!!
}
// Would want to implement some conversion to other types, still using schema
}
如您所見,我無法將converterToDst
的第一個參數的類型A
“配對”到schema
參數的type-argument。 但是,我認為方法定義應該是安全的,兩者可以一起使用。 我得到的錯誤是
[...] type mismatch;
[error] found : a.type (with underlying type A)
[error] required: _
convertToDst(s.aToB(a), s.bSchema)
所以我有兩個問題:
a
上線標記(1)和(2)? 我認為對於第一個問題,但仍然使用asInstanceOf,如果我能在match-case中命名類型參數,我可以解決一些問題,例如case s: MappedSchema[A,B] =>
。 但這看起來不可能(由於類型擦除可能是一個壞主意)
還要注意,在發現這個問題之后,我發現奇怪的是案例(3)編譯:(來自IntelliJ) ai
是Any
而c.bSchema
是Schema[B]
。
我認為使用類型類更安全和可擴展。
下面是使用這種方法重寫代碼,如果您在使用實際用例時遇到任何問題,請告訴我。
trait Dst
sealed trait Schema[A] {
def convertToDst(input: A): Dst
final def contraMap[B](bToA: B => A): Schema[B] = new Schema[B] {
override final def convertToDst(input: B): Dst =
this.convertToDst(input = bToA(input))
}
}
object Schema {
final implicit val IntSchema: Schema[Int] =
new Schema[Int] {
override final def convertToDst(input: Int): Dst =
???
}
implicit def listSchema[A](implicit aSchema: Schema[A]): Schema[List[A]] =
new Schema[List[A]] {
override final def convertToDst(input: List[A]): Dst =
???
}
def convertToDst[A](a: A)(implicit schema: Schema[A]): Dst =
schema.convertToDst(input = a)
}
您可以在模式中命名類型參數:
case s: SeqSchema[a1] =>
convertSeqToDst(a.asInstanceOf[Seq[a1]].map{ ai => // (2)
convertToDst(ai, s.bSchema) // (3)
})
case s: MappedSchema[a1,b1] =>
convertToDst(s.aToB(a.asInstanceOf[a1]), s.bSchema) // (4)
我發現奇怪的是案例(3)編譯:(來自intellij)ai是Any而c.bSchema是Schema [B]。
因為你將Schema
聲明為協變( [+A]
),所以Schema[B]
也是Schema[Any]
,無論B
是什么。
您可以通過將第一個類型參數固定到A
來幫助編譯器推斷類型:
case s: MappedSchema[A, _] =>
convertToDst(s.aToB(a), s.bSchema)
適用於Scala 2.13和2.12。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.