你可以做
val nc: notAContainer = notAContainer(status.pending, "abc")
val nc1: notAContainer = notAContainer(status.ready, "def")
container(nc.status, nc.commonValue)
container(nc1.status, nc1.commonValue)
您将拥有类型的值container[status]
(而不是其子类型container[status.pending]
, container[status.ready]
)。
以防万一,如果它不适合您的用例,请解释原因(为什么需要 types 的值container[status.pending]
,container[status.ready]
如何使用它们等)。
如果这真的很重要(例如,如果类的构造函数对不同的container
行为不同S
),那么例如您可以指定类型参数并向下转换
container[status.pending](nc.status.asInstanceOf[status.pending], nc.commonValue)
container[status.ready](nc1.status.asInstanceOf[status.ready], nc1.commonValue)
或者你可以使用模式匹配
nc.status match {
case s: status.ready => container[status.ready](s, nc.commonValue)
case s: status.pending => container[status.pending](s, nc.commonValue)
}
但结果将有 type container[status]
。
您甚至可以使用宏自动进行模式匹配
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def matchStatus(nc: notAContainer): container[status] = macro matchStatusImpl
def matchStatusImpl(c: blackbox.Context)(nc: c.Tree): c.Tree = {
import c.universe._
val s = TermName(c.freshName("s"))
val cases = typeOf[status].typeSymbol.asClass.knownDirectSubclasses.map(symb => {
val typ = symb.asType.toType
val pattern = pq"$s: $typ"
cq"$pattern => container.apply[$typ]($s, $nc.commonValue)"
})
q"""
$nc.status match {
case ..$cases
}
"""
}
matchStatus(nc)
//scalac: App.this.nc.status match {
// case (s$macro$1 @ (_: App1.status.pending.type)) => App1.container.apply[App1.status.pending.type](s$macro$1, App.this.nc.commonValue)
// case (s$macro$1 @ (_: App1.status.ready.type)) => App1.container.apply[App1.status.ready.type](s$macro$1, App.this.nc.commonValue)
//}
模式匹配(手动或使用宏)发生在运行时。所以在编译时我们不能有 types 的值container[status.pending]
,container[status.ready]
只有 type 的值container[status]
。
如果你真的需要一个类型的值,container[status.pending]
或者container[status.ready]
你可以在运行时使用反射编译
import scala.reflect.runtime.{currentMirror => cm}
import scala.reflect.runtime.universe.Quasiquote
import scala.tools.reflect.ToolBox
object App {
val tb = cm.mkToolBox()
sealed trait status extends Product with Serializable
object status{
case object pending extends status
case object ready extends status
type ready = ready.type
type pending = pending.type
}
case class container[+S <: status](status : S, commonValue: String)
case class notAContainer(status : status, commonValue:String)
val nc: notAContainer = notAContainer(status.pending, "abc")
def main(args: Array[String]): Unit = {
// tb.eval(tb.parse(
// s"""import App._
// |val c = container[status.${nc.status}](status.${nc.status}, "${nc.commonValue}")
// |println(c)
// |""".stripMargin))
// val clazz = nc.status.getClass
// val classSymbol = cm.classSymbol(clazz)
val classSymbol = cm.reflect(nc.status).symbol
// val moduleSymbol = cm.moduleSymbol(clazz)
val moduleSymbol = classSymbol.owner.info.decl(classSymbol.name.toTermName) // (*)
tb.eval(q"""
import App._
val c = container[${classSymbol.toType}]($moduleSymbol, ${nc.commonValue})
println(c)
""")
}
}
(*) 1 2
在 quasiquotes 内q"..."
,变量c
具有 type container[status.pending]
。