与scala中的存在类型混淆

时间:2014-07-09 06:06:23

标签: scala existential-type

我正在努力理解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 [Int],Array [String]等。Array[T forSome {type T}]表示数组[Any]。但根据我的测试代码的结果,我看不出这种差异,编译错误信息也令人困惑。 required: T的含义是什么?如果有人能给出详细解释,我很感激,谢谢!

2 个答案:

答案 0 :(得分:3)

  

我被告知sed -i '$s/,$//' select_stmnt.txt 表示任何类型的数组,例如Array [Int],Array [String]等。

那是对的。您可能会惊讶地发现值Array[T] forSome {type T}被接受为Array(1,2.2,"3")类型的值,即使Array[T] forSome {type T}显然不是Array(1,2.2,"3")类型的值也不是{{1} }}。要了解正在发生的事情,请让Scala告诉我Array[Int]的推断类型:

Array[String]

啊哈!因此,有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}]在特定<type expression involving T> forSome {type T}实例化的所有类型的超类型。所以<type expression involving T>TArray[T] forSome {type T}等的超类型。由于Array[Int]Array[String]T forSome {type T}等的超类型, Int是所有类型的超类型,即String

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}]

请注意,由于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实例化为a,但在进行类型检查时,它不是重要的值的真实类型,它是声明的类型。 T的子类型是Any吗?不,因为String可能是Ta无法放入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吗?是的,所以作业成功了。

关于存在性的最后一件事:当String只需要实例化一次时,类型推断最有效。之前我们看到Any生成了一对具有相同(未知)类型的元素。我真的很惊讶这是有效的。在下面非常相似的示例中,T(a(0), a(1))也应该具有相同的类型,因此赋值应该成功,但它不会。

a(0)

为了向Scala显示这样的赋值是类型安全的,我们可以将它包装在适用于任何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)
               ^

我们现在可以通过将我们的函数应用于Array[T]来执行赋值,这次它确实成功了。

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

答案 1 :(得分:0)

它与Array[Any]不同。 Array[T forSome { type T; }]表示您并不关心Array内的哪种类型。您可以在数组上编写泛型方法,例如:def swap(arr : Array[T forSome { type T; }]) = arr(0) = arr(1);。但是数组类型保持已知,所有表达式都是相对于它进行了类型检查。