假设:
scala> trait Resource[A] { def f: String }
defined trait Resource
scala> case class Foo(x: String)
defined class Foo
然后暗示:
scala> implicit def fooToResource(foo: Foo): Resource[Foo] =
new Resource[Foo] { def f = foo.x }
以下作品:
scala> implicitly[Resource[Foo]](Foo("foo")).f
res2: String = foo
我定义了一个函数:
scala> def f[A](x: A)(implicit ev: Resource[A]): String = ev.f
f: [A](x: A)(implicit ev: Resource[A])String
但是,以下代码无法编译:
scala> f(Foo("foo"))
<console>:17: error: could not find implicit value for parameter ev: Resource[Foo]
f(Foo("foo"))
其次,然后我尝试了:
scala> f2(Foo("bippy"))
<console>:17: error: could not find implicit value for parameter ev: Resource[Foo]
f2(Foo("bippy"))
^
最后,我尝试了:
scala> def g(foo: Foo)(implicit ev: Resource[Foo]): String = ev.f
g: (foo: Foo)(implicit ev: Resource[Foo])String
scala> g(Foo("5"))
<console>:17: error: could not find implicit value for parameter ev: Resource[Foo]
g(Foo("5"))
^
然而,它也失败了。我该如何解决f
?
答案 0 :(得分:5)
好的Peter Neyens&#39;回答,这不是一个类型类,这是一个隐式转换,你应该避免 - 应该有一些警告,要求你导入scala.language.implicitConversions。
作为补充,这就是第一个implicitly
起作用的原因:
隐含的只是:
def implicitly[T](implicit ev: T): T = e
当您在不提供参数的情况下编写implicitly[T]
时,它将在范围内查找隐式类型T
并返回它。但是,您使用参数隐式调用(我相信没有正当理由这样做),因此它只会返回您的参数Foo("foo")
,Foo
的实例。除非您明确声明T
应该是资源[Foo]。如果您编写了类型归属,例如(Foo("foo"): Resource[Foo])
,那么它的工作方式也会相同。 implicitly
与此无关。
关键是Foo("foo")
不是预期类型Resource[Foo]
,而只是Foo
。编译器会拒绝它,除了此时,您在上面定义的隐式转换启动,并且您的Foo
实例转换为Resource[Foo]
。然后,您可以拨打f
。
接下来,您致电f(Foo("foo"))
。有一个隐含参数,但是这一次,你不提供它。所以编译器会查找一个(虽然它第一次没有这样做),并且因为没有这样的实例,所以失败了。
答案 1 :(得分:4)
implicit def fooToResource
不是类型类实例,但如果您提供Foo
,则会返回一个,这就是以下行的原因:
implicitly[Resource[Foo]](Foo("foo")).f
解决方案是更改Resource.f
函数以获取A
类型的参数:
trait Resource[A] {
def f(a: A): String
}
然后,您可以为Resource
定义Foo
类型类实例,如下所示:
case class Foo(x: String)
implicit val fooResource = new Resource[Foo] {
def f(foo: Foo) = foo.x
}
我们可以重写f
以使用更改后的Resource
:
def f[A](a: A)(implicit resA: Resource[A]): String = resA.f(a)
你需要做什么(我认为):
f(Foo("hello world")) // String = hello world