代码之家  ›  专栏  ›  技术社区  ›  Julian

(Co)在Scala中列表上的差异和堆栈上的差异?

  •  3
  • Julian  · 技术社区  · 14 年前

    var s: Stack[_ <: Number] = new Stack[Integer]; 
    s.push(new Integer(1)); //compile-error: type mismatch; found :Integer required: _$bqjyh where type _$bqjyh <: Number
    s.push(null); //compile-error: type mismatch; found   : Null(null) required: _$2 where type _$2 <: Objects.Vehicle
    

    这相当于Java中的协变集合(covariant collection),因为使用了通配符;它的确切类型是未知的,因此我们不能向堆栈中添加某些内容。

    但对于列表,我不会得到相同的错误:

       var list: List[_ <: Number] = Nil;
       var intList : List[Integer] = new Integer(1) :: Nil;
       list = intList ; //no error
       list = new Float(2) :: vehicles;  //even float allowed
    

    现在我甚至可以添加一个 float 但事实上我相信 list 是一个 List Integers ,所以不是 Floats

    1) 为什么列表允许这样,而堆栈不允许这样?这是因为cons(:)操作符吗?

    2) 列表的类型是什么?是动态的吗?

    3) 为什么Scala中允许这样做而Java中不允许这样做?

    null 在Java中不起作用,因为泛型类型只允许引用类型)

    2 回复  |  直到 14 年前
        1
  •  6
  •   sepp2k    14 年前

    :: 不是变异操作。这意味着 x :: xs 将返回类型的列表 List[ commonSupertypeOf[ typeOf[x], elementTypeOf[xs] ] ] (这不是实际的scala代码,但我希望我的观点能被理解),但它不会改变 xs . 如果 有类型 List[Float] x 有类型 Integer x::xs 将有类型 List[Numeric] ,但是 列表[浮动]

    add 然而,这是一个变异操作。 xs.add(x) 将添加 整数 Stack 谁的类型是 Stack<Float> ,这显然是一个错误。

    这就解释了为什么 x::xs 并不危险。现在解释一下为什么它会打勾:

    的本质 :: List[A] def :: [B >: A] (x: B) : List[B] .

    这意味着对于任何类型 A B 哪里 B类 A , 给定类型的值 B类 以及类型列表 A someInteger :: someFloats Numeric Float 一切正常。

    用java术语来说 <B supertypeOf A> List<B> prepend(B item) 除了那个 supertypeOf

        2
  •  4
  •   user382157 user382157    14 年前

    Scala语言使用定义站点差异注释,而不是使用站点差异注释。列表的协方差在列表特征中定义,而堆栈不定义为协方差。通常,可变集合 是协变的,因为这会导致在集合中插入新元素的类型错误(这是Java协变数组的一个主要问题)