【问题标题】:Why does Array[T forSome { type T; }] mean Array[Any]为什么 Array[T forSome { type T; }] 表示数组[任何]
【发布时间】:2014-06-14 16:32:24
【问题描述】:

我在看"Existential types in Scala"的文章,发现有些看不懂:

Array[T] forSome { type T; }
Array[T forSome { type T; }]

它们看起来几乎相同,但实际上却大不相同。第一个是所有数组的类型,无论它们的类型参数如何。第二个是 Array[Any]。

为什么它们如此不同,尤其是为什么第二个表示Array[Any]

【问题讨论】:

    标签: scala type-systems existential-type


    【解决方案1】:

    改变括号的位置可能会大大改变含义,这不足为奇。有点像切换∃和∀

    第一个意思是:有一些类型T,所以这是一个Array[T]。所以Array[String]Array[Int] 等都可以满足这一点。数组是同构的,但我们不知道是哪种类型。

    第二个意思是:对于数组的每个元素,都有一些类型T,因此该元素的类型是T。这根本没有限制,所以它只是Array[Any]。将forSome 放在方括号内可能会很有用,例如

    Array[Set[T] forSome {type T}]
    

    这意味着数组的元素都是集合,但在同一个数组中可能同时存在一个 Int 的 Set 和一个 String 的 Set。


    关于 Rich Oliver 关于类型擦除的评论:这主要是编译时的事情,它们确实是不同的。在第一种情况下,它是一个我们不知道其元素类型的数组。所以我们不能做例如a(0) = 1,因为它很可能是Array[String]。相反,对于第二种类型,它是Array[Any],并且 a(0) = 1 是可以的。

    【讨论】:

    • 不键入擦除不是否定区分在实践中的重要性吗?我想知道什么时候知道这两种类型的区别真正有用。
    • 啊,好点,我没想到可变。我要提出第二个问题:这种区别对不可变集合/不可变泛型对象有任何价值吗?
    • 不确定,但我认为协变结构的意义不大(这就是我在回答中选择不变“Set”的原因)。实际上,存在类型是对 scala 的较晚添加,主要是为了与 java 通用通配符兼容。协变/逆变不经常有用。
    【解决方案2】:

    区别在于类型系统何时决定 T 是什么。

    也许最好的答案是,尝试在一些代码中使用这两种类型,看看会发生什么,并尝试找出原因。但我会先尝试解释一些类型理论。在这种情况下:

    Array[T forSome { type T; }]
    

    forSome[] 括号内,每个元素本身必须以某种方式解释为T forSome { type T; }。好的,所以Int 对于某些类型的TT,所以你可以在数组中放置IntString 对于某些类型 T 也是 T,因为选择 forSome 一次仅适用于一个元素,所以您可以说 T 这次是 String 而不是 @987654335 @,因此您可以将 String 放入数组中,即使它已经包含 Int

    另一方面,虽然我们可以为数组的任何元素独立选择T,但数组本身的类型已经被选择:它是可以容纳任何东西的数组类型。不能是Array[Int]Array[String]

    但在这种情况下:

    Array[T] forSome { type T; }
    

    类型T 只在数组外决定一次。该数组实际上可以是Array[Int]Array[String]Array[Any]。但是一旦选择了 T 类型,数组的所有元素都必须与该类型保持一致。

    好的,现在让我们尝试一些代码。这是一个例子:

    scala> var a = Array(1,2);
    a: Array[Int] = Array(1, 2)
    
    scala> def first(z : Array[T] forSome { type T }) = z(0);
    first: (z: Array[_])Any
    
    scala> def firstany(z : Array[T forSome { type T }]) = z(0);
    firstany: (z: Array[T forSome { type T }])Any
    
    scala> first(a);
    res0: Any = 1
    
    scala> firstany(a);
    error: type mismatch;
     found   : Array[Int]
     required: Array[T forSome { type T }]
           firstany(a);
                    ^
    

    为什么会出错?因为数组a 的类型为Array[Int],它只能包含Int 类型的东西。那肯定是Array[T] forSome {type T},因为类型系统需要做的就是选择Int 作为类型T。因此first(a) 是可以的。但是如上所述,Array[T forSome { type T }] 不能是Array[Int],所以firstany(a) 是一个错误。

    但以下是可以的,因为Array[Any]Array[T forSome { type T }]

    scala> var b = Array(1, "x");
    b: Array[Any] = Array(1, x)
    
    scala> firstany(b);
    res1: Any = 1
    

    【讨论】:

      猜你喜欢
      • 2019-08-08
      • 2016-06-26
      • 1970-01-01
      • 2021-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多