我想做这样的事情:
def iDontLikeStrings(arg: Not[String]) = {....}
基本上,这应该编译:
iDontLikeStrings(23)
iDontLikeStrings(true)
这不应该编译:
iDontLikeStrings("hello")
这是我的实现(参见要点):
第1步:编码捕获A不是B的子类型
trait NotSubTypeOf[A, B]
注意:我们可以使用中缀表示法来写
A NotSubTypeOf B
而不是 NotSubTypeOf[A, B]
第2步:任意两个类型A和B的证据,A不是B的子类型
implicit def isSub[A, B]: A NotSubTypeOf B = null
第 3 步:定义模糊隐式以在 A 是 B 的子类型(或 A =:= B)的情况下触发编译错误
implicit def iSubAmbig1[A, B >: A]: A NotSubTypeOf B = null
implicit def iSubAmbig2[A, B >: A]: A NotSubTypeOf B = null
第 4 步:为否定类型定义 type-lambda:
type Not[T] = {
type L[U] = U NotSubTypeOf T
}
使用 kind-projector,这可以变得更具可读性。
第5步:完成!
def iDontLikeStrings[A: Not[String]#L](a: A) = {
println(a)
}
iDontLikeStrings(23) // compiles
iDontLikeStrings(true) // compiles
//iDontLikeStrings("hello") // does not compile
最后一行的编译器错误消息可以在 Scala 2.12 中得到更好的处理,它解决了 SI-6806。
此外,所有这些都内置于 Shapeless 中。
在 scala 3 中这变得相当简单:
import scala.util.NotGiven
def iDontLikeStrings[T: [T] =>> NotGiven[T =:= String]](t: T) = {....}