簡體   English   中英

在scala中配對類型參數和參數子類型參數

[英]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)

所以我有兩個問題:

  1. 如何編寫案例(4)編譯?
  2. 不是最重要的,但有沒有辦法不投a上線標記(1)和(2)?

我認為對於第一個問題,但仍然使用asInstanceOf,如果我能在match-case中命名類型參數,我可以解決一些問題,例如case s: MappedSchema[A,B] => 但這看起來不可能(由於類型擦除可能是一個壞主意)

還要注意,在發現這個問題之后,我發現奇怪的是案例(3)編譯:(來自IntelliJ) aiAnyc.bSchemaSchema[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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM