在Scala中对密封特征进行迭代? [英] Iteration over a sealed trait in Scala?

查看:103
本文介绍了在Scala中对密封特征进行迭代?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只是想知道是否有可能迭代Scala中的密封特性? 如果没有,为什么不可能呢?由于特质是密封的,应该可以吗?

I just wanted to know if it is possible to iterate over a sealed trait in Scala? If not, why is it not possible? Since the trait is sealed it should be possible no?

我想做的是这样的:

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中有与之等效的东西吗?

What I want can be done in Java by giving an implementation to the enum values. Is there an equivalent in Scala?

推荐答案

在我看来,这实际上是2.10宏的合适用例:您想访问您知道编译器具有但未公开的信息,并且宏为您提供了一种(合理的)简便的方法来窥视内部.请在此处中查看我的答案,以获取相关的示例(但现在有点过时了),或者仅使用类似的示例:

This is actually in my opinion an appropriate use case for 2.10 macros: you want access to information that you know the compiler has, but isn't exposing, and macros give you a (reasonably) easy way to peek inside. See my answer here for a related (but now slightly out-of-date) example, or just use something like this:

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

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

Now we can write the following:

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

这完全是安全的-如果您请求的类型不是密封的,具有非对象子代的类型等,则会出现编译时错误.

And this is all perfectly safe—you'll get a compile-time error if you ask for values of a type that isn't sealed, has non-object children, etc.

这篇关于在Scala中对密封特征进行迭代?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆