2012-12-02 13 views
30

मैं सिर्फ यह जानना चाहता था कि स्कैला में एक सीलबंद विशेषता पर फिर से चलना संभव है या नहीं? यदि नहीं, तो यह क्यों संभव नहीं है? चूंकि विशेषता सील कर दी गई है, यह संभव नहीं होना चाहिए?स्कैला में एक सीलबंद विशेषता पर इटरेशन?

मुझे क्या करना चाहते हैं ऐसा ही कुछ है:

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

क्या मैं enum मूल्यों के लिए एक कार्यान्वयन देकर जावा में किया जा सकता है चाहता हूँ। क्या स्कला में बराबर है?

+1

नहीं है [इस] (https://gist.github.com/ea5e46a2f392204993fa) क्या आप चाहते हैं? –

+0

धन्यवाद! यह समझने की कोशिश कर रहा था कि मैं केस ऑब्जेक्ट्स का उपयोग क्यों नहीं कर सका;) –

उत्तर

50

इस में वास्तव में है मेरी राय 2.10 मैक्रोज़ के लिए उपयुक्त उपयोग केस है: आप उस जानकारी तक पहुंच चाहते हैं जिसे आप कंपाइलर जानते हैं, लेकिन यह खुलासा नहीं कर रहा है, और मैक्रोज़ आपको अंदर देखने के लिए एक (उचित) आसान तरीका प्रदान करते हैं। (लेकिन अब थोड़ा बाहर की तारीख) एक संबंधित के लिए मेरा उत्तर here देखें उदाहरण है, या बस कुछ इस तरह का उपयोग करें:

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

और यह है:

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

अब हम निम्नलिखित लिख सकते हैं सभी पूरी तरह से सुरक्षित हैं - यदि आप किसी प्रकार के मूल्यों के लिए पूछते हैं, तो आपको संकलन-समय त्रुटि मिल जाएगी, जिसमें गैर-ऑब्जेक्ट बच्चे हैं, आदि

+0

अच्छा :) यह जावा में जितना आसान नहीं है, लेकिन यह काम पूरा हो जाएगा (जब मैं 2.10 का उपयोग करूंगा ...) –

+5

हां, जावा का 'एनम' स्कैला के 'गणना' की तुलना में एक ट्रेन मलबे का तर्कसंगत रूप से कम है, और इस विशेष सम्मान में मुहरबंद लक्षणों से अधिक सुविधाजनक है, लेकिन मैं अभी भी 'एनम' पर स्कैला एडीटी जैसी दृष्टिकोण चुनूंगा हफ्ते का दिन। –

+5

वास्तव में http://stackoverflow.com/questions/18732362/issue-with-using-macros-in-sbt द्वारा हाइलाइट किए गए इस मैक्रो में एक बग है। इसकी आखिरी पंक्तियों को https://gist.github.com/xeno-by/6573434 के साथ प्रतिस्थापित किया जाना चाहिए। –

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 
+0

धन्यवाद। मैंने यही किया है: मूल्यों की एक सूची बनाना –

0

कुछ समस्या जो हल कर सकती है वह संभावना है ओवी के बजाय विधियों को जोड़ने के लिए एक अंतर्निहित रूपांतरण जोड़ें सीलबंद विशेषता है।

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

स्कैला मैक्रोज़ पर आधारित उपर्युक्त समाधान बहुत अच्छा काम करता है।

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

इस answer in another thread देखें:

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] 
}             

इसकी अनुमति देने के लिए, एक इस कोड का उपयोग कर सकते हैं: लेकिन यह तरह के मामलों नहीं करता है। लॉयडेटास Enumeratum library अपेक्षाकृत छोटे बॉयलरप्लेट के साथ an easily available package में जावा एनम जैसी सुविधाएं प्रदान करता है।

1

निराकार 2.1.0-SNAPSHOT के रूप में कोड अपने प्रश्न कार्यों में तैनात @ TravisBrown के question पर एक नजर डालें और प्रगणित एडीटी तत्व है जो उसके बाद चल जा सकता है की एक Set पैदा करता है। मैं संदर्भ में आसानी के लिए यहाँ उनके समाधान सारांश यह होगा (fetchAll है sort of mine :-))

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 
संबंधित मुद्दे