scala - Scala 中密封特征的迭代?

标签 scala enumeration scala-macros sealed

我只是想知道是否可以迭代 Scala 中的密封特征? 如果不能,为什么不可能呢?既然特性被封印了,那应该不可能吧?

我想做的是这样的:

sealed trait ResizedImageKey {

  /**
   * Get the dimensions to use on the resized image associated with this key
   */
  def getDimension(originalDimension: Dimension): Dimension

}

case class Dimension(width: Int,  height: Int)

case object Large extends ResizedImageKey {
  def getDimension(originalDimension: Dimension) = Dimension(1000,1000)
}

case object Medium extends ResizedImageKey{
  def getDimension(originalDimension: Dimension) = Dimension(500,500)
}

case object Small extends ResizedImageKey{
  def getDimension(originalDimension: Dimension) = Dimension(100,100)
}

我想要的可以在 Java 中通过为枚举值提供实现来完成。 Scala 中有等效的吗?

最佳答案

在我看来,这实际上是 2.10 宏的一个合适的用例:您想要访问您知道编译器拥有但未公开的信息,并且宏为您提供了一种(相当)简单的方法来查看内部情况。看我的回答here对于相关的(但现在有点过时)示例,或者只是使用类似这样的内容:

import language.experimental.macros
import scala.reflect.macros.Context

object SealedExample {
  def values[A]: Set[A] = macro values_impl[A]

  def values_impl[A: c.WeakTypeTag](c: Context) = {
    import c.universe._

    val symbol = weakTypeOf[A].typeSymbol

    if (!symbol.isClass) c.abort(
      c.enclosingPosition,
      "Can only enumerate values of a sealed trait or class."
    ) else if (!symbol.asClass.isSealed) c.abort(
      c.enclosingPosition,
      "Can only enumerate values of a sealed trait or class."
    ) else {
      val children = symbol.asClass.knownDirectSubclasses.toList

      if (!children.forall(_.isModuleClass)) c.abort(
        c.enclosingPosition,
        "All children must be objects."
      ) else c.Expr[Set[A]] {
        def sourceModuleRef(sym: Symbol) = Ident(
          sym.asInstanceOf[
            scala.reflect.internal.Symbols#Symbol
          ].sourceModule.asInstanceOf[Symbol]
        )

        Apply(
          Select(
            reify(Set).tree,
            newTermName("apply")
          ),
          children.map(sourceModuleRef(_))
        )
      }
    }
  }
}

现在我们可以编写以下内容:

scala> val keys: Set[ResizedImageKey] = SealedExample.values[ResizedImageKey]
keys: Set[ResizedImageKey] = Set(Large, Medium, Small)

这一切都是完全安全的 - 如果您请求未密封、具有非对象子代等类型的值,您将收到编译时错误。

关于scala - Scala 中密封特征的迭代?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13671734/

相关文章:

class - 如何制作一个Applet类是单例的Scala Applet?

scala - Scala库spec2中“^^”是什么意思

java - 让 Java 代码更加通用

casting - 如何在 "for in"枚举中快速转换元组?

scala - 以无状态方式处理输入事件

postgresql - 斯卡拉.slick.SlickException : JdbcProfile has no JdbcType for type UnassignedType - on Option fields

ios - 通过索引和元素枚举 NSArray 的惯用方法

Scala 宏 : Getting a List of TypeSymbols to be used at runtime

scala - 在生成的宏方法中使用 `this`

scala - 是否可以在 Scala 宏中从 WeakTypeTag 生成 Apply?