模糊的隐含值

lam*_*das 19 scala ambiguity implicit-conversion

我一直以为我理解scala implicits直到最近才遇到奇怪的问题.

在我的应用程序中,我有几个域类

case class Foo(baz: String)
case class Bar(baz: String)
Run Code Online (Sandbox Code Playgroud)

还有一个能够从字符串构造域对象的类.它可以被子类化以进行真正的反序列化并不重要.

class Reads[A] {
  def read(s: String): A = throw new Exception("not implemented")
}
Run Code Online (Sandbox Code Playgroud)

接下来,有隐式反序列化器

implicit val fooReads = new Reads[Foo]
implicit val barReads = new Reads[Bar]
Run Code Online (Sandbox Code Playgroud)

以及将字符串转换为域类之一的帮助器

def convert[A](s: String)(implicit reads: Reads[A]): A = reads.read(s)
Run Code Online (Sandbox Code Playgroud)

不幸的是,在尝试使用它时

def f(s: String): Foo = convert(s)
Run Code Online (Sandbox Code Playgroud)

我得到编译错误

error: ambiguous implicit values:
 both value fooReads of type => Reads[Foo]
 and value barReads of type => Reads[Bar]
 match expected type Reads[A]
       def f(s: String): Foo = convert(s)
                                      ^
Run Code Online (Sandbox Code Playgroud)

对我而言,代码似乎很简单.Reads[Foo]并且Reads[Bar]是一个完全不同的类型,它有什么含糊之处?

真正的代码更加复杂和使用,play.api.libs.json但这个简化版本足以重现错误.

whe*_*ies 13

您在示例中遇到的模糊性是您没有告诉Scalac您想要使用哪一个.您需要替换代码

def f(s: String): Foo = convert[Foo](s)
Run Code Online (Sandbox Code Playgroud)

为了弄清楚要使用哪一个.它无法从返回类型推断出来f.它需要在这里明确.

回应评论

让我在这里扮演魔鬼的拥护者.

trait Foo
case class Bar(s: String) extends Foo
case class Baz(s: String) extends Foo

def f(s: String): Foo = convert(s)
Run Code Online (Sandbox Code Playgroud)

假设有两个BarBaz?我确定那里有更多恶魔般的角落案件,但是这个案件跳出来了.


小智 8

问题是您正在制作通用类型A不变量.相反,这应该是协变的.所以这应该实现如下

case class Foo(baz: String)
case class Bar(baz: String)

// This `+` ? is the only difference  
class Reads[+A] {
  def read(s: String): A = throw new Exception("not implemented")
}

implicit val fooReads = new Reads[Foo]
implicit val barReads = new Reads[Bar]

def convert[A](s: String)(implicit reads: Reads[A]): A = reads.read(s)

def f(s: String): Foo = convert(s)
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅http://docs.scala-lang.org/tutorials/tour/variances.html.