为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

HUX布斯 2019-08-27 13:44:41
在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)

这一切都非常安全 - 如果您要求未密封的类型的值,具有非对象子项等,您将获得编译时错误。


查看完整回答
反对 回复 2019-08-27
?
慕神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(_))
                )
            }
        }
    }}


查看完整回答
反对 回复 2019-08-27
?
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


查看完整回答
反对 回复 2019-08-27
  • 3 回答
  • 0 关注
  • 508 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信