【问题标题】:Exhaustive type matching for sealed trait封闭性状的穷举型匹配
【发布时间】:2017-10-23 16:05:04
【问题描述】:

我希望能够彻底匹配密封特征实现的类型,如下例所示。理想情况下,我想尽可能避免使用反射(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"
  }
}

【问题讨论】:

标签: scala


【解决方案1】:

除非您使用通过“无隐式”排除的类型类,否则无法获取给定类型的值。因此,您需要匹配一个实例。

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()
}

虽然隐含并不可怕:) 看看:

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,只给定一个类型。这是一个非常基本的概念,它使得类类型多态性比子类型更强:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多