在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中有同等的东西吗?
3 回答
大话西游666
TA贡献1817条经验 获得超14个赞
在我看来,这实际上是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
TA贡献1780条经验 获得超1个赞
基于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们
TA贡献1886条经验 获得超2个赞
本机没有这种能力。在更常见的情况下,没有意义,而不是案例对象,你有实际的类作为密封特征的子类。看起来你的情况可能会被枚举更好地处理
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
添加回答
举报
0/150
提交
取消