【问题标题】:scala 2.13 auto implicit resolution errorscala 2.13 自动隐式解析错误
【发布时间】:2020-12-04 06:30:20
【问题描述】:

我正面临这个与 scala 隐式解析相关的奇怪问题

这里是代码sn-p

import scala.collection.Factory
import scala.collection.immutable.Seq

sealed trait A

sealed trait B

case class BImpl() extends B

case class AImpl() extends A

object implicitsContainer {

  type AB = (A, B)

  implicit def toStringAnyTuples[C[X] <: Iterable[X], A <: AB]
  (col: C[A])
  (implicit factory: Factory[(String, Any), C[(String, Any)]])
  : C[(String, Any)] = {

    factory.fromSpecific(col.iterator.map(f => f._1.toString -> f._2))
  }
}

object Main extends App {

  import implicitsContainer._

  def a(f: Seq[(String, Any)]): Seq[(String, Any)] = f

  val w: Seq[(AImpl, BImpl)] = Seq(AImpl() -> BImpl())

  val x: Seq[(String, Any)] = a(w)

  //    Won't compile
  //    val y: Seq[(String, Any)] = a(Seq(AImpl() -> BImpl()))
}

Scala 自动拾取隐式方法

implicit def toStringAnyTuples[C[X] <: Iterable[X], A <: AB](col: C[A])
  (implicit factory: Factory[(String, Any), C[(String, Any)]])
  : C[(String, Any)] = {

    factory.fromSpecific(col.iterator.map(f => f._1.toString -> f._2))
  }

为此:-

  val w: Seq[(AImpl, BImpl)] = Seq(AImpl() -> BImpl())

  val x: Seq[(String, Any)] = a(w)

但会为此引发错误

val y: Seq[(String, Any)] = a(Seq(AImpl() -> BImpl()))

错误是:-

Error:(44, 47) type mismatch;
 found   : (AImpl, BImpl)
 required: (String, Any)
    val y: Seq[(String, Any)] = a(Seq(AImpl() -> BImpl()))

还有一点,如果我从 w

中删除类型
  val w = Seq(AImpl() -> BImpl())

  val x: Seq[(String, Any)] = a(w)

那么这也可以正常工作。 唯一的错误是

val y: Seq[(String, Any)] = a(Seq(AImpl() -> BImpl()))

我正在使用:-

SCALA -> 2.13.3

SBT -> 1.3.13

JAVA -> 14

【问题讨论】:

  • 什么是"test".av?你没有在任何地方定义.av
  • 对不起,我刚刚再次编辑了代码

标签: scala scala-collections implicit scala-2.13


【解决方案1】:

这只是类型推断问题。未推断出Seq.apply 的类型参数。试试

val y: Seq[(String, Any)] = a(Seq[(AImpl, BImpl)](AImpl() -> BImpl()))

val y: Seq[(String, Any)] = a(Seq[(A, B)](AImpl() -> BImpl()))

【讨论】:

  • 有什么办法可以显式省略传递类型参数?例如使用另一个隐式方法或更新旧的隐式方法?
  • @Divyanshu 不确定。为编译器提供提示(如显式指定类型参数或类型归属)是在未推断某些类型时改进 Scala 中类型推断的标准方法。也不推荐隐式转换(与隐式的其他用法相反)。
【解决方案2】:

您所遇到的是 Scala 编译器中推理工作方式的症状。 这是一个显示相同问题的较小示例:

object Test {
  class C[T](x: T)
  implicit def conv(c: C[Int]): C[String] = ???
  def m(cs: C[String]) = 1
  val ci = new C(1)
  def t1: Int = m(ci)       // OK
  def t2: Int = m(new C(1)) // found: Int, expected: String
}

当类型检查new C(1) 时,编译器将预期类型String 下推到类型 检查表达式1,它失败了。在上面的行中,使用预期类型检查 ci C[String] 成功归功于隐式转换。 我的建议是定义一个执行转换的扩展方法,而不是 使转换隐式。为了清楚起见,也建议这样做 - 隐式转换,如 您的示例中定义的问题可能会导致令人惊讶且难以诊断的问题。 在我的示例中,它看起来像这样:

object Test {
  class C[T](x: T)
  implicit class CExt(private val c: C[Int]) extends AnyVal {
    def toCString: C[String] = ???
  }
  def m(cs: C[String]) = 1
  val ci = new C(1)
  def t1: Int = m(ci.toCString)
  def t2: Int = m(new C(1).toCString)
}

【讨论】:

    猜你喜欢
    • 2019-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-27
    • 2020-11-24
    • 2013-12-27
    • 2021-09-29
    • 2021-05-02
    相关资源
    最近更新 更多