迭代 Scala 中的密封特征? [英] Iteration over a sealed trait in 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(_))
)
}
}
}
}
现在我们可以写如下:
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屋!