简体   繁体   English

赋值是隐式协变的吗?

[英]Are assignments implicitly covariant?

This must be a very basic misunderstanding on my part.这一定是我的一个非常基本的误解。 It appears that assignments of parametric types are covariant without any indication on my part that that's what I'd want.参数类型的分配似乎是协变的,但我没有任何迹象表明这就是我想要的。 I'm pasting Scala code for brevity, but it behaves identically in Java.为了简洁起见,我粘贴了 Scala 代码,但它在 Java 中的行为相同。

class Pet
class Fish extends Pet
class Guppy extends Fish
case class Box[T](value: T)
val guppyBox: Box[Fish] = Box(new Guppy()) // Mysteriously, this works.

An instance of type X can only be assigned to a val of type Y if Y is a supertype of X .如果YX的超类型,则类型X的实例只能分配给类型Y的 val。 In my case, this would require Box to be covariant, which I didn't say it is.在我的例子中,这将要求 Box 是协变的,我没有这么说。

I wouldn't be too hung up on this, but it leads to the following odd, in my view, behavior:我不会太在意这个,但在我看来,它会导致以下奇怪的行为:

  def unboxFish(fish: Box[Fish]) = ???

  unboxFish(Box(new Guppy()))       // Oddly, compiles ok
  val guppyBox2 = Box(new Guppy())
  unboxFish(guppyBox2)              // The compilation error I'd expect.

Any help greatly appreciated!非常感谢任何帮助!

Box isn't covariant. Box不是协变的。 What's happening here is that Box(new Guppy()) needs to infer the type parameter for Box , and the inference depends on context.这里发生的是Box(new Guppy())需要推断Box的类型参数,并且推断取决于上下文。 When you do当你做

val guppyBox2 = Box(new Guppy())

it infers the type parameter as Guppy , but when you do它将类型参数推断为Guppy ,但是当您这样做时

val guppyBox: Box[Fish] = Box(new Guppy())

the compiler knows that the RHS should be a Box[Fish] , so it infers that the type parameter should be Fish instead of Guppy , as if you had written编译器知道 RHS 应该是Box[Fish] ,所以它推断类型参数应该是Fish而不是Guppy ,就像你写的一样

val guppyBox: Box[Fish] = Box[Fish](new Guppy())

In Scala type inference goes not only from right to left在 Scala 中,类型推断不仅从右到左

val guppyBox: Box[??] = Box[Something](...)

but also from left to right也是从左到右

val guppyBox: Box[Something] = Box[??](...)

(so it's bidirectional). (所以它是双向的)。

So in所以在

val guppyBox: Box[Fish] = Box(new Guppy())

aka又名

val guppyBox: Box[Fish] = Box[??](new Guppy())

the type parameter ??类型参数?? is inferred to be Fish .被推断为Fish

when does it need explicit type when declare variable in scala? scala声明变量什么时候需要明确类型?

But Box is now not covariant.但是Box现在不是协变的。 Box[Guppy] is not a subtype of Box[Fish] Box[Guppy]不是Box[Fish]的子类型

implicitly[Box[Guppy] <:< Box[Fish]] // doesn't compile

You can't assign a value of type Box[Guppy] to a variable of type Box[Fish]您不能将Box[Guppy]类型的值分配给Box[Fish]类型的变量

val guppyBox: Box[Fish] = Box[Guppy](new Guppy()) // doesn't compile

In your example, Box[Fish] is a subtype of Box[Pet] because Fish is a subtype of Pet.在您的示例中,Box[Fish] 是 Box[Pet] 的子类型,因为 Fish 是 Pet 的子类型。 This is known as covariant type parameterization, and it is allowed in Scala and Java. This is why you are able to assign a Box[Guppy] to a variable of type Box[Fish].这称为协变类型参数化,它在 Scala 和 Java 中是允许的。这就是为什么您可以将 Box[Guppy] 分配给 Box[Fish] 类型的变量。 Regarding the second part of the example, when you pass a Box[Guppy] as an argument to the unboxFish method, the compiler will automatically upcast it to a Box[Fish] as the method expects a Box[Fish] as an argument.关于示例的第二部分,当您将 Box[Guppy] 作为参数传递给 unboxFish 方法时,编译器会自动将其向上转换为 Box[Fish],因为该方法需要 Box[Fish] 作为参数。 However, when you try to pass guppyBox2 to the unboxFish method, the compiler doesn't know that it's a Box[Guppy] because the type of the variable is erased at runtime, so it can't upcast it to a Box[Fish].但是,当您尝试将 guppyBox2 传递给 unboxFish 方法时,编译器不知道它是一个 Box[Guppy],因为变量的类型在运行时被擦除,因此它无法将其向上转换为 Box[Fish] . This is why you get a compilation error.这就是你得到编译错误的原因。

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

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