我试图至少在Scala 2.13中模拟联合类型的某些方面。
到目前为止,满足我需求的最佳方法是coproduct
。唯一的问题是子类型不能按我预期的那样工作。这是一个示例:
import shapeless._
type ISB = Int :+: String :+: Boolean :+: CNil
type ISBSub = Int :+: String :+: CNil
implicitly[ISBSub <:< ISB] // error here
我正在尝试创建一个参数类型为ISB
的方法,并希望此def
也接受ISBSub
。
def test(t: ISB) = ???
test(Coproduct[ISBSub](2)) // not working
有什么办法可以用coproduct
来达到这样的目的?
答案 0 :(得分:8)
鉴于Shapeless对副产品的编码,这种子集关系不可能与子类型相同。而是有一个类型类提供证据,证明一个副产品是另一个副产品的子联盟:
scala> import shapeless._
import shapeless._
scala> type ISB = Int :+: String :+: Boolean :+: CNil
defined type alias ISB
scala> type ISBSub = Int :+: String :+: CNil
defined type alias ISBSub
scala> shapeless.ops.coproduct.Basis[ISB, ISBSub]
res0: shapeless.ops.coproduct.Basis[Int :+: String :+: Boolean :+: shapeless.CNil,Int :+: String :+: shapeless.CNil]{type Rest = Boolean :+: shapeless.CNil} = shapeless.ops.coproduct$Basis$$anon$64@ddd69d2
此类型类还允许您在任一方向上转换任一副产品类型的值:
import shapeless.ops.coproduct.Basis
def shrink[A <: Coproduct, B <: Coproduct](a: A)(implicit ev: Basis[A, B]): Option[B] =
ev(a).toOption
def enlarge[A <: Coproduct, B <: Coproduct](b: B)(implicit ev: Basis[A, B]): A =
ev.inverse(Right(b))
然后:
scala> shrink[ISB, ISBSub](Coproduct[ISB](1))
res0: Option[ISBSub] = Some(Inl(1))
scala> enlarge[ISB, ISBSub](Coproduct[ISBSub](1))
res1: ISB = Inl(1)
通常,有必要浏览shapeless.ops
软件包的内容,以了解对诸如副产品之类的东西支持哪些操作。