【问题标题】:Unexpected type mismatch when using Scala generics使用 Scala 泛型时出现意外的类型不匹配
【发布时间】:2018-11-25 18:35:35
【问题描述】:

我有一个简单的场景,在使用 Scala 泛型时会产生类型不匹配,目前尚不清楚为什么或如何解决它。

trait Foo
case class Bar() extends Foo

trait FooGetter[T <: Foo] {
  def get: T = Bar() // Error
}

错误:

类型不匹配;成立 : 需要酒吧:T

有什么提示吗?

【问题讨论】:

  • 那么您将T 声明为Foo 的子类型,而BarFoo 的子类型。这并不能保证它将是Foo 的任何子类型。例如,如果您创建了另一个类 Bazz,它也从 Foo 扩展,并尝试在 Bazz 中创建参数化的 FooGetter 实例,那么 get 上的 Bar 实例将是类型不匹配。跨度>
  • @LuisMiguelMejíaSuárez 我希望能够从我的方法中返回Bar()。在那种情况下,我应该如何声明它来编译?
  • 好吧,您可以更改类型签名以返回Bar,但随后类型参数和特征本身就变得不必要了。我认为您真正想要的是能够通过调用 FooGeter[Bar].get 之类的东西来隐式地获取 Foot 的正确实例。
  • 我认为您应该编辑问题以更好地解释主要问题,并提供尽可能多的细节。
  • 如果你希望所有返回的东西都被视为Foo,为什么不将返回类型指定为Foo?您仍然可以在实现中返回Bar(),但对于FooGetter 接口的用户,它将是任何Foo

标签: scala generics


【解决方案1】:

这里T &lt;: Foo 表示FooT 类型的上限

如您所见,BarT 之间没有关系,因此不能以隐式方式进行转换。

当然,如果你能保证投射安全,你可以使用asInstanceOf显式投射。

另一方面,当T 是超级而Foo 是孩子时,以下是可以的。

trait FooGetter[T >: Foo] {
  def get: T = Bar()
}

【讨论】:

  • 这在 Scalafiddle 中给了我一个例外 - 请参阅 scalafiddle.io/sf/ZbDrxir/0
  • 重点是new FooGetter[Bar]{}是非法的,因为T &gt;: Foo意味着这里不允许Bar
  • 我的回答是试图找出问题中不允许隐式转换的原因;上限或下限的使用不是我的重点。
  • 好的,但是我的例子看起来会怎么样 - 你能在 ScalaFiddle 中创建一个新版本吗?
  • 请参阅scalafiddle.io/sf/FprLTSu/0。我的回答可能有点误导。
【解决方案2】:

你可以像这样简化代码:

trait Foo
case class Bar() extends Foo

trait FooGetter {
  def get: Foo = Bar()
}

FooGetterFoo 紧密相关,因此将FooGetter 设为通用是没有意义的。 (注意,Bar 是 scala 类型检查器的 Foo。)

【讨论】:

  • 谢谢 - 它是通用的,因为它是实际 getter 的简化,它被子类化并用于其他类型,所以在我的情况下它是必需的。
  • 那么,您能否详细说明问题?
【解决方案3】:

在您的示例中始终有效的是asInstanceOf

trait Foo
case class Bar() extends Foo

trait FooGetter[T <: Foo] {
  def get: T = Bar().asInstanceOf[T]
}

所以这行得通:

println(new FooGetter[Bar]{}.get) // Bar()

但是正如 Seth Tisue 指出的那样:

如果生成的代码不是,那么使用泛型就毫无意义 实际上是通用的。

【讨论】:

  • @ Downvoter - 请你解释一下为什么你不应该使用asInstanceOf[T] - 或者你为什么投反对票 - 我是来学习的,但 Josh Stone 仍然没有正确答案。
  • 您可以asInstanceOf 解决任何类型不匹配的问题。我不认为这算作一个解决方案,因为生成的代码完全是错误的,它恰好在Bar 的情况下工作,但总的来说它是错误的,如果生成的代码是,则根本没有使用泛型的意义'实际上不是通用的。至于我认为什么是正确的答案,@chenzhongpu 的答案似乎与任何人都可以做的一样好,没有更多关于 OP 试图解决的真正问题是什么的问题。另请参阅 Erik 的回答和评论。希望这会有所帮助。
  • @SethTisue 感谢您的解释 - 我同意您的观点并调整了我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-12-21
  • 1970-01-01
  • 2015-04-09
  • 1970-01-01
  • 1970-01-01
  • 2016-10-21
  • 2013-07-06
相关资源
最近更新 更多