【问题标题】:Type variance in multiple type instances of traits多类型特征实例中的类型差异
【发布时间】:2015-02-08 09:05:44
【问题描述】:

考虑

trait Foo[+A, +B]

trait Foo1[+A] extends Foo[A, Nothing]

trait Foo2[+B] extends Foo[Nothing, B]

new Foo1[String] with Foo2[Nothing] 有效。

new Foo1[Nothing] with Foo2[String] 有效。

new Foo1[String] with Foo2[String] 没有:

error: illegal inheritance;
<$anon: Foo1[String] with Foo2[String]> inherits different type instances of trait Foo:
Foo[Nothing,String] and Foo[String,Nothing]
          new Foo1[String] with Foo2[String]
              ^

似乎在第一种情况下,实例是Foo[String, Nothing]的子类型。

同样,在第二种情况下,实例应该是Foo[String, String]的子类型。

这两者有什么区别导致只编译一个?

【问题讨论】:

    标签: scala generics multiple-inheritance covariance traits


    【解决方案1】:

    如果你看到编译器实际上解释得很好:

    : Foo1[String] with Foo2[String]> inherits different type instances of trait Foo:
    Foo[Nothing,String] and Foo[String,Nothing]
                  new Foo1[String] with Foo2[String]
    

    解释第一个:

    new Foo1[String] with Foo2[Nothing]
    

    看看这个例子:

    scala> val x = new Foo1[String] with Foo2[Nothing]
    x: Foo1[String] with Foo2[Nothing] = $anon$1@58651fd0
    
    scala> val y:Foo[String, Nothing] = x
    y: Foo[String,Nothing] = $anon$1@58651fd0
    

    根据规范,多个with 特征的实例化从左到右发生。所以首先 Foo1 被实例化。做new Foo1[String] 会给你Foo[String, Nothing]with Foo2[Nothing] 给你Foo[Nothing, Nothing]。现在Foo 的第一个类型参数是协变的。简而言之,这是有效的:

    scala> val a = new Foo[Nothing, Nothing]{}
    a: Foo[Nothing,Nothing] = $anon$1@134593bf
    
    scala> val b:Foo[String, Nothing] = a
    b: Foo[String,Nothing] = $anon$1@134593bf
    

    因此您可以使用 Foo[String, Nothing] 代替 Foo[Nothing, Nothing]。这使您能够实例化y

    如果发生:

    new Foo1[String] with Foo2[String]
    

    new Foo1[String] 给出Foo[String, Nothing]with Foo2[String]Foo[Nothing, String]。而且它们都是矛盾的(由于它的第二个参数:

    with Foo2[String] (Foo[Nothing, String]) 变为 Foo[String, String]。

    scala> val p :Foo[String, String] = new Foo[Nothing, String]{}
    p: Foo[String,String] = $anon$1@39529185
    

    但是 Foo[String, String] 不能变成 Foo[String, Nothing]。 (val p :Foo[String, Nothing] = new Foo[Nothing, String]{} 失败)

    因此错误。


    变体中 如果 Foo 的第一个参数不是不变的,那么它就不起作用:

    scala> trait Foo[A, +B]
    defined trait Foo
    
    scala> trait Foo1[A] extends Foo[A, Nothing]
    defined trait Foo1
    
    scala> trait Foo2[+B] extends Foo[Nothing, B]
    defined trait Foo2
    
    scala> new Foo1[String] with Foo2[Nothing]
    <console>:11: error: illegal inheritance;
     <$anon: Foo1[String] with Foo2[Nothing]> inherits different type instances of trait Foo:
    Foo[Nothing,Nothing] and Foo[String,Nothing]
                  new Foo1[String] with Foo2[Nothing]
    

    反方差 如果 Foo 在它的第二种类型上是逆变的,那么这两个语句都有效

    scala> trait Foo[+A, -B]
    defined trait Foo
    
    scala> trait Foo1[+A] extends Foo[A, Nothing]
    defined trait Foo1
    
    scala> trait Foo2[-B] extends Foo[Nothing, B]
    defined trait Foo2
    
    scala> new Foo1[String] with Foo2[String]
    res0: Foo1[String] with Foo2[String] = $anon$1@77468bd9
    
    scala> new Foo1[String] with Foo2[Nothing]
    res1: Foo1[String] with Foo2[Nothing] = $anon$1@51016012
    

    它之所以有效,是因为现在:Foo[String, String] 可以变成 Foo[String, Nothing]

    【讨论】:

    • “Foo[String, Nothing] 不 <: foo string>new Foo[String, Nothing] {}: Foo[String, String] 工作。
    • @PaulDraper 你正在做相反的事情:)。它是val v:Foo[String, Nothing] = new Foo[String, String] {},但它失败了。
    • @PaulDraper 是的,同意。我的意思是显示协方差关系而不是&lt;:。错误,因此昨天自己纠正了
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-08-15
    • 2018-01-15
    • 2016-04-17
    • 1970-01-01
    • 2019-12-08
    • 2021-07-02
    • 2015-03-30
    相关资源
    最近更新 更多