我希望能够详尽地匹配密封特性的实现类型,如下例所示。理想情况下,我希望尽可能避免使用反射(TypeTags)和隐式转换。有没有办法彻底匹配密封特性的类型?
object DataTypes {
sealed trait StrFy {
def stringify: String
}
final case class StrFyString(s: String) extends StrFy {
def stringify = s
}
final case class StrFyInt(i: Int) extends StrFy {
def stringify = i.toString
}
def stringifyThings[T <: StrFy](values: T*): String = {
val label = T match {
case StrFyString => "string"
case StrFyInt => "integer"
// cases that don't extend StrFy cause a compile error
}
"The " + label + " values are: " + values.map(_.stringify.fold("")(_+", "+_))
}
def printStringified(): Unit = {
println(stringifyThings(StrFyString("foo"), StrFyString("bar"))) // should print: "the string values are: foo, bar"
println(stringifyThings(StrFyInt(1), StrFyInt(2), StrFyInt(3))) // should print: "the integer values are: 1, 2, 3"
}
}
答案 0 :(得分:2)
除非您使用由“无暗示”排除的类型类,否则无法获取给定类型的值。因此,您需要匹配实例。
object DataTypes extends App {
sealed trait StrFy {
def stringify: String
}
final case class StrFyString(s: String) extends StrFy {
def stringify = s
}
final case class StrFyInt(i: Int) extends StrFy {
def stringify = i.toString
}
def stringifyThings[T <: StrFy](values: T*): String = {
def label(value: T) = value match {
case _:StrFyString => "string"
case _:StrFyInt => "integer"
// cases that don't extend StrFy cause a compile error
}
// Will throw if values is empty
"The " + label(values.head) + " values are: " + values.map(_.stringify).mkString(", ")
}
def printStringified(): Unit = {
println(stringifyThings(StrFyString("foo"), StrFyString("bar"))) // should print: "the string values are: foo, bar"
println(stringifyThings(StrFyInt(1), StrFyInt(2), StrFyInt(3))) // should print: "the integer values are: 1, 2, 3"
}
printStringified()
}
Implicits并不那么可怕:)看看:
object DataTypes extends App {
sealed trait StrFy[T] {
def stringify(value: T): String
def label: String
}
implicit object StrFyString extends StrFy[String] {
override def stringify(value: String): String = value
override def label: String = "string"
}
implicit object StrFyInt extends StrFy[Int] {
override def stringify(value: Int): String = value.toString
override def label: String = "integer"
}
def stringifyThings[T: StrFy](values: T*): String = {
val strFy = implicitly[StrFy[T]]
// Safe even on empty values
"The " + strFy.label + " values are: " + values.map(strFy.stringify).mkString(", ")
}
def printStringified(): Unit = {
println(stringifyThings("foo", "bar")) // should print: "the string values are: foo, bar"
println(stringifyThings(1, 2, 3)) // should print: "the integer values are: 1, 2, 3"
}
printStringified()
}
编译器为您执行“模式匹配”,在给定输入类型的情况下提供正确的实例。
您会看到类型类允许您获取一个值label
,只给出一个类型。这是一个非常基本的概念,使类型类多态性强于子类型:)