복붙노트

[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)
}

내가 원하는 것은 열거 값으로 구현을 제공하여 자바에서 수행 할 수 있습니다. 스칼라에 해당하는이 있습니까?

해결법

  1. ==============================

    1.당신이 컴파일러가 알고있는 정보에 대한 액세스를 원하지만, 노출되지 않으며, 매크로는 당신에게 내부 들여다 할 수있는 (합리적) 쉬운 방법을 제공 : 이것은 내 의견으로는 실제로 2.10 매크로에 대한 적절한 사용 사례입니다. 관련 여기 내 대답을 참조하십시오 (하지만 지금은 약간 아웃 오브 날짜) 예를 들어, 아니면 그냥 이런 식으로 뭔가를 사용 :

    당신이 컴파일러가 알고있는 정보에 대한 액세스를 원하지만, 노출되지 않으며, 매크로는 당신에게 내부 들여다 할 수있는 (합리적) 쉬운 방법을 제공 : 이것은 내 의견으로는 실제로 2.10 매크로에 대한 적절한 사용 사례입니다. 관련 여기 내 대답을 참조하십시오 (하지만 지금은 약간 아웃 오브 날짜) 예를 들어, 아니면 그냥 이런 식으로 뭔가를 사용 :

    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)
    

    그리고 이것은 등 모두 완벽하게 안전, 지저분 당신이 봉인되지 않은 유형의 값을 요구하는 경우 컴파일 타임 오류가 발생,이 개체가 아닌 아이들이다

  2. ==============================

    2.스칼라 매크로에 따라 위에서 언급 한 솔루션은 잘 작동합니다. 그러나이 같은 사례를하지 않습니다 :

    스칼라 매크로에 따라 위에서 언급 한 솔루션은 잘 작동합니다. 그러나이 같은 사례를하지 않습니다 :

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

    3.기본적으로이에 대한 기능은 없습니다. 대신 경우의 당신이 당신의 밀봉 특성의 서브 클래스로 실제 수업을했다 객체보다 일반적인 경우에 이해가되지 것입니다. 귀하의 경우가 더 열거에 의해 처리 될 수있는 것 같습니다

    기본적으로이에 대한 기능은 없습니다. 대신 경우의 당신이 당신의 밀봉 특성의 서브 클래스로 실제 수업을했다 객체보다 일반적인 경우에 이해가되지 것입니다. 귀하의 경우가 더 열거에 의해 처리 될 수있는 것 같습니다

    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
    
  4. ==============================

    4.볼품 2.1.0-SNAPSHOT 현재 @ TravisBrown의 질문을 살펴보십시오 코드를 자신의 질문 작품에 게시하고 통과 할 수있는 열거 ADT 요소 세트를 생성합니다. 내가 참조의 편의를 위해 여기에 자신의 솔루션을 다시 덮습니다 (fetchAll은 :-) 광산의 일종이다)

    볼품 2.1.0-SNAPSHOT 현재 @ TravisBrown의 질문을 살펴보십시오 코드를 자신의 질문 작품에 게시하고 통과 할 수있는 열거 ADT 요소 세트를 생성합니다. 내가 참조의 편의를 위해 여기에 자신의 솔루션을 다시 덮습니다 (fetchAll은 :-) 광산의 일종이다)

    import shapeless._
    
      trait AllSingletons[A, C <: Coproduct] {
        def values: List[A]
      }
    
      object AllSingletons {
        implicit def cnilSingletons[A]: AllSingletons[A, CNil] =
          new AllSingletons[A, CNil] {
            def values = Nil
          }
    
        implicit def coproductSingletons[A, H <: A, T <: Coproduct](implicit
                                                                    tsc: AllSingletons[A, T],
                                                                    witness: Witness.Aux[H]
                                                                   ): AllSingletons[A, H :+: T] =
          new AllSingletons[A, H :+: T] {
            def values: List[A] = witness.value :: tsc.values
          }
      }
    
      trait EnumerableAdt[A] {
        def values: Set[A]
      }
    
      object EnumerableAdt {
        implicit def fromAllSingletons[A, C <: Coproduct](implicit
                                                          gen: Generic.Aux[A, C],
                                                          singletons: AllSingletons[A, C]
                                                         ): EnumerableAdt[A] =
          new EnumerableAdt[A] {
            def values: Set[A] = singletons.values.toSet
          }
      }
    
      def fetchAll[T](implicit ev: EnumerableAdt[T]):Set[T] = ev.values
    
  5. ==============================

    5.다른 스레드에서이 대답을 참조하십시오. Lloydmetas Enumeratum 라이브러리는 상대적으로 작은 보일러와 쉽게 가능한 패키지의 기능과 같은 자바 열거를 제공합니다.

    다른 스레드에서이 대답을 참조하십시오. Lloydmetas Enumeratum 라이브러리는 상대적으로 작은 보일러와 쉽게 가능한 패키지의 기능과 같은 자바 열거를 제공합니다.

  6. ==============================

    6.또한 문제를 해결할 수 있습니다 뭔가 대신 밀봉 특성 반복의, 열거에 방법을 추가하는 암시 적 변환을 추가 할 수있는 가능성이다.

    또한 문제를 해결할 수 있습니다 뭔가 대신 밀봉 특성 반복의, 열거에 방법을 추가하는 암시 적 변환을 추가 할 수있는 가능성이다.

    object SharingPermission extends Enumeration {
      val READ = Value("READ")
      val WRITE = Value("WRITE")
      val MANAGE = Value("MANAGE")
    }
    
    
    /**
     * Permits to extend the enum definition and provide a mapping betweet SharingPermission and ActionType
     * @param permission
     */
    class SharingPermissionExtended(permission: SharingPermission.Value) {
    
      val allowRead: Boolean = permission match {
        case SharingPermission.READ => true
        case SharingPermission.WRITE => true
        case SharingPermission.MANAGE => true
      }
      val allowWrite: Boolean = permission match {
        case SharingPermission.READ => false
        case SharingPermission.WRITE => true
        case SharingPermission.MANAGE => true
      }
      val allowManage: Boolean = permission match {
        case SharingPermission.READ => false
        case SharingPermission.WRITE => false
        case SharingPermission.MANAGE => true
      }
    
      def allowAction(actionType: ActionType.Value): Boolean = actionType match {
        case ActionType.READ => allowRead
        case ActionType.WRITE => allowWrite
        case ActionType.MANAGE => allowManage
      }
    
    }
    
    object SharingPermissionExtended {
      implicit def conversion(perm: SharingPermission.Value): SharingPermissionExtended = new SharingPermissionExtended(perm)
    }
    
  7. from https://stackoverflow.com/questions/13671734/iteration-over-a-sealed-trait-in-scala by cc-by-sa and MIT license