【问题标题】:Why ambiguous reference error while using Left without parameters type?为什么在使用不带参数类型的 Left 时出现模棱两可的引用错误?
【发布时间】:2021-06-09 21:06:29
【问题描述】:

我在尝试练习 scala 面试问题时发现“对重载定义的模糊引用”。

我试图找到导致编译错误的以下代码块的结果:

代码:

for {
  v1 <- Left[Int,Int](1)
  v2 <- Right(2)
  v3 <- Right(3)
  v4 <- Left(4)
} yield v1 + v2 + v3 + v4

错误:

<pastie>:17: error: ambiguous reference to overloaded definition,
both method + in class Int of type (x: Char)Int
and  method + in class Int of type (x: Byte)Int
match argument types (Nothing)
} yield v1 + v2 + v3 + v4
                     ^

当我们仅在 v1 字段上指定类型而不在 v4 上指定类型时,为什么 Scala 编译器会给出模糊引用错误

我还尝试了 v1 和 v4 中具有不同参数类型的以下版本,并且成功了!

for {
  v1 <- Left[String,Int]("1")
  v2 <- Right(2)
  v3 <- Right(3)
  v4 <- Left[Int, Int](4)
} yield v1 + v2 + v3 + v4

输出是:

res20: scala.util.Either[Any,Int] = Left(1)

我尝试了另一个版本,但也导致了错误:

for {
  v1 <- Left(1)
  v2 <- Right(2)
  v3 <- Right(3)
  v4 <- Left(4)
} yield v1 + v2 + v3 + v4

输出:

<console>:17: error: value + is not a member of Nothing
       } yield v1 + v2 + v3 + v4

在这里,LeftRight 的 for 理解到底是如何工作的?为什么第一个和最后一个案例在我的示例中不起作用?

【问题讨论】:

  • 你在 eithers 上写了一个for,因此编译器需要同时跟踪 leftright i> 类型。您的示例没有提供这些类型,也没有为编译器提供足够的信息来正确推断它们。例如v4 &lt;- Left(4) v4 的类型应该是什么?对你来说很明显它应该是 Int 但对于编译器来说它简单不知道,所以它假设 Nothing 但你不能总结一个 Int 带有 Nothing。一般来说,这不是问题,因为通常您不会有硬编码值(因为您可以手动减少表达式),而是调用方法。
  • @Luis Miguel Mejía Suárez,很好的解释来理解这个问题。但是为什么 scala compile 在我的示例中只为 v1 字段指定类型的第一种情况不会产生任何错误?
  • 不确定您的意思?第一个版本确实会产生错误。

标签: scala for-comprehension


【解决方案1】:

这是因为没有通用的推断类型,并且您没有为所有 Either 指定类型。

所以

scala> for (v1 <- Right(2)) yield v1
res13: scala.util.Either[Nothing,Int] = Right(2)

解决方案是给它们通用类型

for {
  v1 <- Left[Int,Int](1)
  v2 <- Right[Int,Int](2)
  v3 <- Right[Int,Int](3)
  v4 <- Left[Int,Int](4)
} yield v1 + v2 + v3 + v4

这给出了Left(1)。这个结果是有道理的,因为Either 是右偏的,并且可以理解为flatMap

根据文档: “要么是右偏,这意味着 Right 被假定为默认情况下进行操作。如果是 Left,则 map、flatMap、... 等操作返回 Left 值不变”https://www.scala-lang.org/api/2.12.0/scala/util/Either.html

【讨论】:

  • 当我尝试使用 String 字段类型 v1 &lt;- Left[String,Int]("1") 时,为什么 scala 编译器不会为我的问题中的第二个示例生成任何错误
  • 因为它现在可以将类型推断为Either[Any,Int],使其成为一种常见类型。但就结果而言,它仍然值得怀疑,因为当您将产量更改为yield v1yield v2 时,它们都会返回Left(1)。我认为这是Either 本身的问题
  • Left[Int,Int](1)也可以写成Left(1).withRight[Int]
  • 好吧,我去阅读了文档,这很好地解释了它“要么是右偏,这意味着右被假定为默认情况下进行操作。如果是左,像地图这样的操作, flatMap, ... 返回 Left 值不变"
  • @kanielc @Luis Miguel Mejía Suárez:感谢您提供的内容丰富的讨论。您能否用最后评论中的结论更新答案。所以我可以接受答案。
猜你喜欢
  • 1970-01-01
  • 2011-07-07
  • 1970-01-01
  • 2013-01-18
  • 2011-07-23
  • 1970-01-01
  • 2011-04-24
  • 2013-11-04
  • 1970-01-01
相关资源
最近更新 更多