繁体   English   中英

与scala中的存在类型混淆

[英]confusion with existential types in scala

我在努力理解scala中的存在类型,但无法弄清楚。 这是我的测试代码:

scala> val a: Array[T] forSome {type T} = Array(1,2.2,"3")
a: Array[_] = Array(1, 2.2, 3)

scala> val b: Array[T forSome {type T}] = Array(1,2.2,"3")
b: Array[T forSome { type T }] = Array(1, 2.2, 3)

scala> a(0)
res35: Any = 1

scala> b(0)
res36: Any = 1

scala> a(0) = "x"
<console>:10: error: type mismatch;
 found   : String("x")
 required: T
              a(0) = "x"
                     ^

scala> b(0) = "x"

有人告诉我Array[T] forSome {type T}表示任何类型的Array,例如Array [Int],Array [String]等Array[T forSome {type T}]表示Array [Any]。 但是根据测试代码的结果,我看不到这种差异,并且编译错误消息也令人困惑。 required: T什么required: T是什么意思? 如果有人可以提供详细的解释,我非常感谢,谢谢!

有人告诉我Array[T] forSome {type T}表示任何类型的Array,例如Array [Int],Array [String]等。

没错 您可能会惊讶地发现,即使Array(1,2.2,"3")显然是Array(1,2.2,"3") Array[T] forSome {type T}Array[T] forSome {type T}的值,也接受Array(1,2.2,"3")作为Array[T] forSome {type T}类型的值不是Array[Int]类型或Array[String]类型的值。 要了解发生了什么,让我们问一下Scala它为Array(1,2.2,"3")推断出什么类型:

scala> val x = Array(1,2.2,"3")
x: Array[Any] = Array(1, 2.2, 3)

啊哈! 所以有一个类型T ,即Any ,因此x具有类型Array[T] 这就是为什么Array(1,2.2,"3")被接受为Array[T] forSome {type T}类型的值的Array[T] forSome {type T}

Array[T forSome {type T}]表示Array [Any]

也正确。 <type expression involving T> forSome {type T}的类型<type expression involving T>是所有类型的超类型,其中在特定T实例化<type expression involving T> 因此, Array[T] forSome {type T}Array[Int]Array[String]等的超类型。由于T forSome {type T}IntString等的超类型,所以T forSome {type T}是所有类型(也称为Any )的超类型。

 scala> a(0) res35: Any = 1 

您可能想知道为什么结果的类型为Any而不是T 与以下内容进行比较:

scala> (a(0), a(1))
res0: (T, T) forSome { type T } = (1,2.2)

如您所见, Array[T]的元素的类型确实是T 只是当我们仅从数组中获取单个元素时,其类型为T forSome { type T } ,它简化为Any

 scala> b(0) res36: Any = 1 

这次非常期待类型Any ,因为Array[T forSome {type T}]的元素Array[T forSome {type T}]T forSome {type T} ,也就是Any

请注意,因为forSome在方括号内,所以一对元素的类型...

scala>  (b(0), b(1))
res1: (Any, Any) = (1,2.2)

...是(T forSome {type T}, T forSome {type T}) ,又名(Any, Any)

 scala> a(0) = "x" <console>:10: error: type mismatch; found : String("x") required: T a(0) = "x" ^ 

您分配给Array[T]的值的类型必须是T的子类型。 我们知道值aT实例化为Any ,但是在进行类型检查时,重要的不是值的实型,而是它的声明类型。 并且StringT的子类型吗? 不可以,因为a可以是Array[Int]并且不能将String放入Array[Int]

 scala> b(0) = "x" scala> b res2: Array[T forSome { type T }] = Array(x, 2.2, 3) 

您分配给Array[T forSome {type T}]值的类型必须是T forSome {type T}的子类型,也称为Any StringAny的子类型吗? 是的,所以分配成功。

关于存在性的最后一件事:当T只需要实例化一次时,类型推断最有效。 之前我们看到(a(0), a(1))产生了一对具有相同(未知)类型的元素。 实际上,我对此功能感到惊讶。 在以下非常相似的示例中, a(0)a(1)也应该具有相同的类型,因此赋值应该成功,但事实并非如此。

scala> a(0) = a(1)
<console>:12: error: type mismatch;
 found   : (some other)T(in value a)
 required: T(in value a)
       a(0) = a(1)
               ^

为了显示Scala这种分配是类型安全的,我们可以将其包装在适用于任何Array[T]的函数中:

scala> def modifyArray[T](arr: Array[T]) =
     |   arr(0) = arr(1)
modifyArray: [T](arr: Array[T])Unit

现在,我们可以通过应用我们的函数来执行任务a ,而这一次它确实成功。

scala> modifyArray(a)

scala> a
res3: Array[_] = Array(2.2, 2.2, 3)

它与Array[Any] Array[T forSome { type T; }] Array[T forSome { type T; }]表示您不在乎Array内部的类型。 您可以在Array上编写通用方法,例如: def swap(arr : Array[T forSome { type T; }]) = arr(0) = arr(1); 但是数组类型仍然是已知的,并且所有表达式都经过类型检查。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM