【问题标题】:Scala compiler is complaining about type mismatch for generic parameter on method levelScala 编译器在方法级别抱怨泛型参数的类型不匹配
【发布时间】:2018-02-28 07:34:21
【问题描述】:

为什么 Scala 编译器无法编译 next code

trait Profile {}
class SomeProfile extends Profile

trait Foo {
  def get[T <: Profile]: Option[T]
}

object Example {
  val foo: Foo = new Foo {
    // This works (but might give runtime exception), but it is not ugly? :)
    def get[T <: Profile]: Option[T] = Some((new SomeProfile).asInstanceOf[T])
  }

  val foo2: Foo = new Foo {
    // This does not compile with type mismatch :(
    def get[T <: Profile]: Option[T] = Some(new SomeProfile)
  }
}

编译器说:

type mismatch;
 found   : Playground.this.SomeProfile
 required: T

但是SomeProfileT,不是吗?

更新:

我想用确切的类型实现这个 trait DatabaseConfigProvider 并以这种方式进行:

val dc: DatabaseConfig[JdbcProfile] = ???
val prov = new DatabaseConfigProvider {
  def get[P <: BasicProfile] = dc.asInstanceOf[DatabaseConfig[P]]
}

因为asInstanceOf而看起来很丑。

【问题讨论】:

  • 你能说明是哪一行导致了错误吗?

标签: scala types generic-programming scala-generics


【解决方案1】:

您错误地声明了输入参数。试试下面:

trait Profile {}
class SomeProfile() extends Profile

trait Foo {
  def get[T >: Profile]: Option[T]
}

object Example {
  val foo2: Foo = new Foo {
    override def get[T >: Profile]: Option[T] = Some(new SomeProfile())
  }
}

:&gt; 的作用说明,您可以在 Stackoverflow 中轻松找到(例如:What does [B >: A] do in Scala?

【讨论】:

  • 输入参数声明没有错误,我想要&lt;: => 一个上限,
  • 你想如何使用你的get方法。如果你想声明为val e:Option[Profile] = foo2.get(编译错误)。
【解决方案2】:

您的方法get 的输出类型由调用者定义。您添加了类型边界(如T &lt;: Profile),但这仅意味着对调用者的限制。如果调用者要求Profile 的另一个子类型而不是您所转换的子类型,则任何转换(如您所做的)都将在运行时失败。

如果您提供有关您期望获得的结果的更多详细信息,我可以扩展答案并提供具体建议如何获得它。

【讨论】:

  • 我检查了实现并来到了 SlickApi。正如我所见,asInstanceOf 被积极使用。所以,假设你别无选择。唯一的问题是,有人明确表示Usually, you shouldn't need to create instances of DatabaseConfigProvider`。相反,你应该依赖依赖注入。`但是如果你需要,看起来你除了asInstanceOf之外别无选择
  • 我需要它来进行集成测试,我可以在代码中定义数据库配置,而不是在配置文件中。我只是好奇为什么编译器无法弄清楚?
  • 弄清楚什么?输出类型是通用的。如果没有强制转换,您将尝试返回特定类型,这是错误的。换句话说,对于返回 Profile 的任何子项(取决于调用上下文)的方法,您返回特定类型。
  • 这个约束T &lt;: Profile(必须是Profile的子类型)是否受到尊重?因为SomeProfileProfile (class SomeProfile extends Profile) 的子类型(实现)?
  • 没有。类型绑定指定调用者的边界。因此,呼叫者以get[AnyProfileChild] 进行的任何呼叫都是有效的。然后您返回一种特定类型。
猜你喜欢
  • 2021-06-27
  • 2013-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-29
  • 2013-12-21
  • 1970-01-01
相关资源
最近更新 更多