提供子类实例代替超类时出现 Scala 错误?
Scala error when providing subclass instance in place of superclass?
我只是在 scala 中尝试一些东西,我写了这段代码
object Main:
def main(args: Array[String]): Unit =
val dInt: Data[Int] = IntData(1)
val dString: Data[String] = StringData("hello")
val Data(deconstructedInt) = dInt // unapply
val Data(deconstructedString) = dString // unapply
println(deconstructedInt)
println(deconstructedString)
sealed trait Data[+T]:
def get: T
case class IntData(get: Int) extends Data[Int]
case class StringData(get: String) extends Data[String]
object Data:
def apply[T](input: T): Data[T] = input match {
case i: Int => IntData(i) //compile error here
case s: String => StringData(s) //compile error here
}
def unapply[T](d: Data[T]): Option[String] = d match {
case IntData(get) => Some(s"int data => get = $get")
case StringData(get) => Some(s"string data => get = $get")
}
我在代码注释的位置得到这个错误
Found: IntData
Required: Data[T]
case i: Int => IntData(i)
为什么我会收到此错误,IntData
(或 StringData
)不是 Data
的子类吗?
IntData
是 Data[Int]
的子类型。因此,如果 T
不是 Int
,那么 IntData
是 而不是 Data[T]
的子类型。现在,您可能会说,如果 input
匹配第一种情况,那么显然 T
是 Int
。但是编译器并不聪明地意识到这一点!
您可以尝试使用 Scala 3 的新匹配类型:
type DataOf[T] = T match {
case Int => IntData
case String => StringData
}
def apply[T](input: T): DataOf[T] = input match {
case i: Int => IntData(i)
case s: String => StringData(s)
}
另一种选择是联合类型:
def apply(input: Int | String): Data[Int | String] = input match {
case i: Int => IntData(i)
case s: String => StringData(s)
}
但是,这样做会丢失类型信息。使用匹配类型解决方案,apply(42)
被推断为具有类型 IntData
。使用联合类型解决方案,推断类型为 Data[Int | String]
.
编译器通过这种方式连接 T
之间的点并且它有效:
object Main:
def main(args: Array[String]): Unit =
val dInt: Data[Int] = IntData(1)
val dString: Data[String] = StringData("hello")
val Data(deconstructedInt) = dInt // unapply
val Data(deconstructedString) = dString // unapply
println(deconstructedInt)
println(deconstructedString)
sealed trait Data[+T]:
def get: T
case class IntData[T <: Int](get: T) extends Data[T]
case class StringData[T <: String](get: T) extends Data[T]
object Data:
def apply[T](input: T): Data[T] = input match {
case i: Int => IntData(i)
case s: String => StringData(s)
}
def unapply[T](d: Data[T]): Option[String] = d match {
case IntData(get) => Some(s"int data => get = $get")
case StringData(get) => Some(s"string data => get = $get")
}
我只是在 scala 中尝试一些东西,我写了这段代码
object Main:
def main(args: Array[String]): Unit =
val dInt: Data[Int] = IntData(1)
val dString: Data[String] = StringData("hello")
val Data(deconstructedInt) = dInt // unapply
val Data(deconstructedString) = dString // unapply
println(deconstructedInt)
println(deconstructedString)
sealed trait Data[+T]:
def get: T
case class IntData(get: Int) extends Data[Int]
case class StringData(get: String) extends Data[String]
object Data:
def apply[T](input: T): Data[T] = input match {
case i: Int => IntData(i) //compile error here
case s: String => StringData(s) //compile error here
}
def unapply[T](d: Data[T]): Option[String] = d match {
case IntData(get) => Some(s"int data => get = $get")
case StringData(get) => Some(s"string data => get = $get")
}
我在代码注释的位置得到这个错误
Found: IntData
Required: Data[T]
case i: Int => IntData(i)
为什么我会收到此错误,IntData
(或 StringData
)不是 Data
的子类吗?
IntData
是 Data[Int]
的子类型。因此,如果 T
不是 Int
,那么 IntData
是 而不是 Data[T]
的子类型。现在,您可能会说,如果 input
匹配第一种情况,那么显然 T
是 Int
。但是编译器并不聪明地意识到这一点!
您可以尝试使用 Scala 3 的新匹配类型:
type DataOf[T] = T match {
case Int => IntData
case String => StringData
}
def apply[T](input: T): DataOf[T] = input match {
case i: Int => IntData(i)
case s: String => StringData(s)
}
另一种选择是联合类型:
def apply(input: Int | String): Data[Int | String] = input match {
case i: Int => IntData(i)
case s: String => StringData(s)
}
但是,这样做会丢失类型信息。使用匹配类型解决方案,apply(42)
被推断为具有类型 IntData
。使用联合类型解决方案,推断类型为 Data[Int | String]
.
编译器通过这种方式连接 T
之间的点并且它有效:
object Main:
def main(args: Array[String]): Unit =
val dInt: Data[Int] = IntData(1)
val dString: Data[String] = StringData("hello")
val Data(deconstructedInt) = dInt // unapply
val Data(deconstructedString) = dString // unapply
println(deconstructedInt)
println(deconstructedString)
sealed trait Data[+T]:
def get: T
case class IntData[T <: Int](get: T) extends Data[T]
case class StringData[T <: String](get: T) extends Data[T]
object Data:
def apply[T](input: T): Data[T] = input match {
case i: Int => IntData(i)
case s: String => StringData(s)
}
def unapply[T](d: Data[T]): Option[String] = d match {
case IntData(get) => Some(s"int data => get = $get")
case StringData(get) => Some(s"string data => get = $get")
}