在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個贊
本機沒有這種能力。在更常見的情況下,沒有意義,而不是案例對象,你有實際的類作為密封特征的子類??雌饋砟愕那闆r可能會被枚舉更好地處理
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
提交
取消
