3 回答

TA貢獻(xiàn)1817條經(jīng)驗(yàn) 獲得超14個(gè)贊
在我看來,這實(shí)際上是2.10宏的一個(gè)合適的用例:你想要訪問你知道編譯器有的信息,但是沒有公開,而宏給你一個(gè)(合理)簡(jiǎn)單的方法來查看內(nèi)部。請(qǐng)?jiān)诖颂幉榭次业拇鸢敢垣@取相關(guān)(但現(xiàn)在稍微過時(shí))的示例,或者只使用以下內(nèi)容:
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(_)) ) } } }}
現(xiàn)在我們可以寫下面的內(nèi)容:
scala> val keys: Set[ResizedImageKey] = SealedExample.values[ResizedImageKey]keys: Set[ResizedImageKey] = Set(Large, Medium, Small)
這一切都非常安全 - 如果您要求未密封的類型的值,具有非對(duì)象子項(xiàng)等,您將獲得編譯時(shí)錯(cuò)誤。

TA貢獻(xiàn)1780條經(jīng)驗(yàn) 獲得超1個(gè)贊
基于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(_)) ) } } }}

TA貢獻(xiàn)1886條經(jīng)驗(yàn) 獲得超2個(gè)贊
本機(jī)沒有這種能力。在更常見的情況下,沒有意義,而不是案例對(duì)象,你有實(shí)際的類作為密封特征的子類。看起來你的情況可能會(huì)被枚舉更好地處理
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
或者,您可以自己創(chuàng)建枚舉,為方便起見,可能將其放在伴隨對(duì)象中
object ResizedImageKey{ val values = Vector(Small, Medium, Large)}println(ResizedImageKey.values.mkString(",") //prints Small,Medium,Large
添加回答
舉報(bào)