scala 不明确的隐含值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25431878/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Ambiguous implicit values
提问by lambdas
I've been thinking I understand scala implicits until recently faced strange problem.
我一直在想我理解 Scala 的隐式,直到最近遇到奇怪的问题。
In my application I have several domain classes
在我的应用程序中,我有几个域类
case class Foo(baz: String)
case class Bar(baz: String)
And a class that is able to construct domain object from a string. It could be subclassed to do real deserialization it doesn't matter.
以及一个能够从字符串构造域对象的类。它可以被子类化以进行真正的反序列化,这无关紧要。
class Reads[A] {
def read(s: String): A = throw new Exception("not implemented")
}
Next, there are implicit deserializers
接下来,还有隐式解串器
implicit val fooReads = new Reads[Foo]
implicit val barReads = new Reads[Bar]
And a helper to convert strings to one of domain classes
以及将字符串转换为域类之一的助手
def convert[A](s: String)(implicit reads: Reads[A]): A = reads.read(s)
Unfortunatelly, when trying to use it
不幸的是,在尝试使用它时
def f(s: String): Foo = convert(s)
I get compiler errors like
我收到编译器错误,例如
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)
^
To me code seems simple and right. Reads[Foo]and Reads[Bar]is a completely different types, what is ambiguous about it?
对我来说,代码似乎简单而正确。Reads[Foo]而且Reads[Bar]是完全不同的类型,有什么含糊之处呢?
The real code is much more complicated and uses play.api.libs.jsonbut this simplified version is sufficient to reproduce the error.
真正的代码要复杂得多并且使用,play.api.libs.json但这个简化的版本足以重现错误。
采纳答案by wheaties
The ambiguity you're encountering in your example is that you didn't tell Scalac which one you wanted to use. You need to replace your code with
您在示例中遇到的歧义是您没有告诉 Scalac 您想使用哪个。您需要将代码替换为
def f(s: String): Foo = convert[Foo](s)
in order for it to figure out which one to use. It can't infer from the return type of f. It needs to be explicit here.
以便它确定使用哪个。它无法从 的返回类型推断出来f。这里需要明确。
Response to comment
回复评论
Let me play devil's advocate here.
让我在这里扮演魔鬼的代言人。
trait Foo
case class Bar(s: String) extends Foo
case class Baz(s: String) extends Foo
def f(s: String): Foo = convert(s)
which implicit does it use assuming there is one defined for both Barand Baz? I'm sure there's more devilish corner cases out there but this one jumps out to me.
假设有一个为Barand定义的,它使用哪个隐式Baz?我敢肯定那里有更多邪恶的角落案例,但这个让我跳了出来。
回答by wheaties
The problem is that you are making generic type A invariant. Instead this should be covariant. So this should be implemented as follows
问题是您正在使泛型类型 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)
Please refer to http://docs.scala-lang.org/tutorials/tour/variances.htmlfor more information.
有关更多信息,请参阅http://docs.scala-lang.org/tutorials/tour/variances.html。

