我试图理解 Scala3 新的“多元平等”功能。在比较不同类型时,我遇到了不一致的行为。
情况 1. 比较 Int 和 String:
val x = 1
val y = "One"
x == y // gives compilation error -> "Values of types Int and String cannot be compared with == or !="
Run Code Online (Sandbox Code Playgroud)
scala.language.strictEquality
案例 2. 比较两个案例类:
case class Cat(catname: String)
case class Dog(dogname: String)
val d = Dog("Frank")
val c = Cat("Morris")
d == c // false, but it compiles
Run Code Online (Sandbox Code Playgroud)
我知道我需要import scala.language.strictEquality
在 case2 中强制执行多重平等。但为什么 case1 不需要呢?
请注意
情况1。summon[CanEqual[Int, String]]
即使不导入也无法编译scala.language.strictEquality
案例2.summon[CanEqual[Cat, Dog]]
scala.language.strictEquality
但是a) 类型 class 的实例CanEqual
由编译器生成(以及scala.reflect.ClassTag
, scala.reflect.TypeTest
, scala.ValueOf
, scala.deriving.Mirror.Product
, scala.deriving.Mirror.Sum
, scala.deriving.Mirror
)
val specialHandlers = List(
defn.ClassTagClass -> synthesizedClassTag,
defn.TypeTestClass -> synthesizedTypeTest,
defn.CanEqualClass -> synthesizedCanEqual,
defn.ValueOfClass -> synthesizedValueOf,
defn.Mirror_ProductClass -> synthesizedProductMirror,
defn.Mirror_SumClass -> synthesizedSumMirror,
defn.MirrorClass -> synthesizedMirror)
Run Code Online (Sandbox Code Playgroud)
b) 问题在于,当类型参数L
, R
of之一CanEqual[-L, -R]
是数值类 ( Byte
, Short
, Char
, Int
, Long
, Float
, Double
) 时,处理方式有所不同:
val synthesizedCanEqual: SpecialHandler = (formal, span) =>
...
if canComparePredefined(arg1, arg2)
|| !Implicits.strictEquality && explore(validEqAnyArgs(arg1, arg2))
...
Run Code Online (Sandbox Code Playgroud)
请注意,如果在此之前给出答案,则是否打开canComparePredefined
并不重要。strictEquality
c)canComparePredefined
调用
def canComparePredefinedClasses(cls1: ClassSymbol, cls2: ClassSymbol): Boolean =
...
if cls1.isPrimitiveValueClass then
if cls2.isPrimitiveValueClass then
cls1 == cls2 || cls1.isNumericValueClass && cls2.isNumericValueClass
else
cmpWithBoxed(cls1, cls2)
else if cls2.isPrimitiveValueClass then
cmpWithBoxed(cls2, cls1)
...
else
false
Run Code Online (Sandbox Code Playgroud)
L
请注意,这里如果,之一R
是数值类,则另一个也必须是数值类(考虑装箱),以便summon[CanEqual[Int, Int]]
, summon[CanEqual[Double, Double]]
,summon[CanEqual[Int, Double]]
编译但summon[CanEqual[Int, String]]
不编译。
归档时间: |
|
查看次数: |
226 次 |
最近记录: |