在Scala中对密封特性进行迭代?

在Scala中对密封特性进行迭代?

我只是想知道是否有可能在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中有同等的东西吗?


HUX布斯
浏览 490回答 3
3回答

大话西游666

在我看来,这实际上是2.10宏的一个合适的用例:你想要访问你知道编译器有的信息,但是没有公开,而宏给你一个(合理)简单的方法来查看内部。请在此处查看我的答案以获取相关(但现在稍微过时)的示例,或者只使用以下内容:import language.experimental.macrosimport scala.reflect.macros.Contextobject 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)这一切都非常安全 - 如果您要求未密封的类型的值,具有非对象子项等,您将获得编译时错误。

慕神8447489

基于Scala Macros的上述解决方案效果很好。然而,它不像以下情况:sealed trait ImageSize                            object ImageSize {                                     case object Small extends ImageSize                  case object Medium extends ImageSize                 case object Large extends ImageSize                  val values = SealedTraitValues.values[ImageSize]}为此,可以使用以下代码:import language.experimental.macrosimport scala.reflect.macros.Contextobject 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 siblingSubclasses: List[Symbol] = scala.util.Try {                 val enclosingModule = c.enclosingClass.asInstanceOf[ModuleDef]                 enclosingModule.impl.body.filter { x =>                     scala.util.Try(x.symbol.asModule.moduleClass.asClass.baseClasses.contains(symbol))                         .getOrElse(false)                 }.map(_.symbol)             } getOrElse {                 Nil             }             val children = symbol.asClass.knownDirectSubclasses.toList ::: siblingSubclasses            if (!children.forall(x => x.isModuleClass || x.isModule)) c.abort(                 c.enclosingPosition,                 "All children must be objects."             ) else c.Expr[Set[A]] {                 def sourceModuleRef(sym: Symbol) = Ident(                     if (sym.isModule) sym else                         sym.asInstanceOf[                             scala.reflect.internal.Symbols#Symbol                             ].sourceModule.asInstanceOf[Symbol]                 )                 Apply(                     Select(                         reify(Set).tree,                         newTermName("apply")                     ),                     children.map(sourceModuleRef(_))                 )             }         }     }}

MM们

本机没有这种能力。在更常见的情况下,没有意义,而不是案例对象,你有实际的类作为密封特征的子类。看起来你的情况可能会被枚举更好地处理object ResizedImageKey extends Enumeration {   type ResizedImageKey = Value   val Small, Medium, Large = Value   def getDimension(value:ResizedImageKey):Dimension =        value match{          case Small => Dimension(100, 100)          case Medium => Dimension(500, 500)          case Large => Dimension(1000, 1000)}println(ResizedImageKey.values.mkString(",") //prints Small,Medium,Large或者,您可以自己创建枚举,为方便起见,可能将其放在伴随对象中object ResizedImageKey{   val values = Vector(Small, Medium, Large)}println(ResizedImageKey.values.mkString(",") //prints Small,Medium,Large
打开App,查看更多内容
随时随地看视频慕课网APP