在Scala中如何使用否定类型?

6 浏览
0 Comments

在Scala中如何使用否定类型?

我想做类似这样的事情:\n

def iDontLikeStrings(arg: Not[String]) = {....}

\n基本上,这应该能编译通过:\n

iDontLikeStrings(23) 
iDontLikeStrings(true)

\n而这不应该能编译通过:\n

iDontLikeStrings("hello") 

0
0 Comments

问题:如何在Scala中使用否定类型(negation type)?

在Scala 3中,解决这个问题变得相当简单。可以使用以下代码来定义一个否定类型:

import scala.util.NotGiven
def iDontLikeStrings[T: [T] => NotGiven[T =:= String]](t: T) = {....}

原因:问题的出现可能是因为在Scala中,没有直接提供否定类型的语法。否定类型是一种类型约束,它指定了一个类型参数不应该是另一个特定类型的子类型。然而,Scala 3引入了`NotGiven`类型,可以用于实现否定类型。

解决方法:为了在Scala中使用否定类型,可以使用`NotGiven`类型。在上述代码中,`iDontLikeStrings`函数使用了一个类型参数`T`,并使用`[T] => NotGiven[T =:= String]`约束来指定`T`不应该是`String`类型。这样,当传入一个`String`类型的参数时,编译器将会报错。

0
0 Comments

在Scala中如何使用否定类型?

在Scala中,我们经常需要判断一个类型是否是另一个类型的子类型。然而,Scala并没有直接提供否定类型的功能。本文将介绍如何在Scala中实现否定类型,并给出具体的代码实现。

首先,我们需要定义一个trait来表示A不是B的子类型:

trait NotSubTypeOf[A, B]

注意,我们可以使用中缀表示法来写成A NotSubTypeOf B而不是NotSubTypeOf[A, B]

接下来,我们需要为任意的两个类型A和B提供证据,证明A不是B的子类型:

implicit def isSub[A, B]: A NotSubTypeOf B = null

然后,我们需要定义两个模棱两可的隐式转换函数,以在A是B的子类型(或A等于B)的情况下引发编译错误:

implicit def iSubAmbig1[A, B >: A]: A NotSubTypeOf B = null
implicit def iSubAmbig2[A, B >: A]: A NotSubTypeOf B = null

接下来,我们需要定义一个类型lambda来表示否定类型:

type Not[T] = {
  type L[U] = U NotSubTypeOf T
}

使用kind-projector插件可以使代码更易读。

最后,我们可以使用否定类型来定义一个函数,该函数只接受不是String类型的参数:

def iDontLikeStrings[A: Not[String]#L](a: A) = {
  println(a)
}
iDontLikeStrings(23)   // 编译通过
iDontLikeStrings(true) // 编译通过
//iDontLikeStrings("hello") // 编译错误

注意,在Scala 2.12中,编译器错误消息的质量得到了改善。

需要注意的是,这种方法只适用于静态已知的类型。在某些情况下可能会出现问题,例如def test[A](a :A) = foo(a); test("hello")。在Scala 2中,这个问题无法解决,除非使用宏。

总之,通过以上步骤,我们可以在Scala中实现否定类型,并在编译时对类型进行判断和限制。在实际应用中,这种方法可以帮助我们更好地控制类型的使用和转换。

0