Enforce type difference

2019-01-01 00:40发布

In Scala I can enforce type equality at compile time. For example:

case class Foo[A,B]( a: A, b: B )( implicit ev: A =:= B )

scala> Foo( 1, 2 )
res3: Foo[Int,Int] = Foo(1,2)

scala> Foo( 1, "2" )
<console>:10: error: Cannot prove that Int =:= java.lang.String.

Is there a way to enforce that type A and type B should be different ?

标签: scala types
7条回答
骚的不知所云
2楼-- · 2019-01-01 01:22

This is not an answer, just the beginnings of what I could think is an answer. The code below will return either an Yes or an No depending on whether the types are equal or not, if you ask for implicitly[AreEqual[A,B]]. How to go from there to actually making a check I haven't been able to figure out. Maybe the whole approach is doomed, maybe someone can make something out of it. Mind you, implicitly[No[A, B]] will always return something, one can't use that. :-(

class AreEqual[A, B]
trait LowerPriorityImplicits {
  implicit def toNo[A : Manifest, B : Manifest]: No[A, B] = No[A, B]
}
object AreEqual extends LowerPriorityImplicits {
  implicit def toYes[A, B](implicit ev: A =:= B, m1: Manifest[A], m2: Manifest[B]): Yes[A, B] = Yes[A, B]
}

case class Yes[A : Manifest, B : Manifest]() extends AreEqual[A, B] {
  override def toString: String = "Yes(%s, %s)" format (manifest[A].toString, manifest[B].toString)
}
case class No[A : Manifest, B : Manifest]() extends AreEqual[A, B] {
  override def toString: String = "No(%s, %s)" format (manifest[A].toString, manifest[B].toString)
}

Test:

scala> implicitly[AreEqual[String, Option[String]]]
res0: AreEqual[String,Option[String]] = No(java.lang.String, scala.Option[java.lang.String])

scala> implicitly[AreEqual[String, String]]
res1: AreEqual[String,String] = Yes(java.lang.String, java.lang.String)
查看更多
登录 后发表回答