Scala 为密封类型的所有子类型提供隐式
在我的应用程序中,我有多个case类和对象,它们是密封特征层次结构的一部分。我用它们作为阿克卡语的信息 在通过websocket发送之前,这些类需要转换为用户友好的形式 以前我使用大模式匹配在单个位置转换它们,但随着类型数量的增加,我希望使用隐式转换:Scala 为密封类型的所有子类型提供隐式,scala,scalaz,shapeless,scala-macros,scala-macro-paradise,Scala,Scalaz,Shapeless,Scala Macros,Scala Macro Paradise,在我的应用程序中,我有多个case类和对象,它们是密封特征层次结构的一部分。我用它们作为阿克卡语的信息 在通过websocket发送之前,这些类需要转换为用户友好的形式 以前我使用大模式匹配在单个位置转换它们,但随着类型数量的增加,我希望使用隐式转换: object Types { sealed trait Type case object SubType1 extends Type case object SubType2 extends Type case object Su
object Types {
sealed trait Type
case object SubType1 extends Type
case object SubType2 extends Type
case object SubType3 extends Type
trait Converter[T] {
def convert(t: T): Int
}
}
object Implicits {
import Types._
implicit object Type1Coverter extends Converter[SubType1.type] {
override def convert(t: SubType1.type): Int = 1
}
implicit object Type2Coverter extends Converter[SubType2.type] {
override def convert(t: SubType2.type): Int = 2
}
implicit object Type3Coverter extends Converter[SubType3.type] {
override def convert(t: SubType3.type): Int = 3
}
}
object Conversion {
import Types._
def convert[T: Converter](t: T): Int = {
implicitly[Converter[T]].convert(t)
}
def convert2[T <: Type](t: T)(implicit ev1: Converter[SubType1.type], ev2: Converter[SubType2.type], ev3: Converter[SubType3.type]): Int = {
t match {
case t1@SubType1 =>
implicitly[Converter[SubType1.type]].convert(t1)
case t2@SubType2 =>
implicitly[Converter[SubType2.type]].convert(t2)
case t3@SubType3 =>
implicitly[Converter[SubType3.type]].convert(t3)
}
}
}
我很想知道是否有什么“神奇”的方法可以在不编写宏的情况下自动生成像
convert2
这样的东西。也许已经有一个库提供了这样的宏 由于在编译时没有关于t类型的信息,所以必须在运行时工作
如果将转换器置于a中,可以使用中介绍的技术执行以下操作:
导入无形状_
trait allsingleton[A,C由于在编译时没有关于t类型的信息,所以必须在运行时工作
如果将转换器置于a中,可以使用中介绍的技术执行以下操作:
导入无形状_
特征所有单态[A,C这确实是一个不错的解决方案,但不是我想要的,因为它没有经过编译时检查。我会尝试了解这里发生了什么,因为它看起来非常有用。谢谢!你唯一不能检查的是,你的每个case对象是否都有一个typeclass实例。如果你找到了这样做的方法,请告诉我!:)我做了一些事情像这样使用宏:这确实是一个不错的解决方案,但不是我想要的解决方案,因为它没有经过编译时检查。我将尝试了解这里发生了什么,因为它看起来非常有用。谢谢!你唯一不能检查的是,你的每个case对象是否都有一个typeclass实例。如果你找到一种方法,让我来看看知道吗!:)我用宏做了类似的事情:
import Types._
import Conversion._
import Implicits._
val t1 = SubType1
val x1: Int = convert(t1)
val t: Type = SubType2 // T is of type Type
//Is it possible to handle that?
//val x: Int = convert(t)
val y: Int = convert2(t)
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 = 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 = singletons.values.toSet
}
}
object Types {
sealed trait Type
case object SubType1 extends Type
case object SubType2 extends Type
case object SubType3 extends Type
sealed abstract class Converter[T <: Type: ClassTag] {
def convert(t: T): Int
def convertibleObjectClass = implicitly[ClassTag[T]].runtimeClass
}
object Implicits {
implicit object Type1Converter extends Converter[SubType1.type] {
override def convert(t: SubType1.type): Int = 1
}
implicit object Type2Converter extends Converter[SubType2.type] {
override def convert(t: SubType2.type): Int = 2
}
// let's pretend you FORGOT to add Type3Converter
// implicit object Type3Converter extends Converter[SubType3.type] {
// override def convert(t: SubType3.type): Int = 3
// }
}
}
object Conversion {
import Types._
val AllConverters: Map[Class[_], Converter[_ <: Type]] = implicitly[EnumerableAdt[Converter[_ <: Type]]].values
.map(c => c.convertibleObjectClass -> c).toMap
// You're sure you have all the converters here but you can't be sure you remembered to add one per subtype... you have to test it
// you are sure this cast doesn't fail anyway because of how you created the map
def findConverter[T <: Type](t: T) = AllConverters.get(t.getClass).asInstanceOf[Option[Converter[T]]]
def convert2[T <: Type](t: T): Option[Int] = findConverter(t).map(_.convert(t))
}
object Test extends App {
import Types._
import Conversion._
val t: Type = SubType2
val t2: Type = SubType3
// works, because a Converter[Subtype2.type] exists
val a: Option[Int] = convert2(t)
// returns None, because a Converter[Subtype3.type] doesn't exist
val b: Option[Int] = convert2(t2)
}