2016-05-15 131 views
1

考虑:使用`implicit def`创建类型实例?

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

回答

4

implicit def fooToResource是不是一个类型的类的实例,但如果你提供一个Foo不会返回一个,那就是下面这行工作的原因:

implicitly[Resource[Foo]](Foo("foo")).f 

一种解决方案是改变Resource.f函数取A类型的参数:

trait Resource[A] { 
    def f(a: A): String 
} 

然后,您可以为Foo如下定义Resource类型的类实例:

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 
5

确定与彼得Neyens的回答,这是不是一个类型类型,这是一个隐式转换,你应该避免 - 应该有一些警告,要求你导入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"))。有一个隐含的参数,但是这次你不提供它。因此,编译器寻找一个(虽然它第一次没有这样的事情),并且因为没有这样的实例失败。

+0

有关'隐式地“的额外信息对我的回答确实是一个很好的补充,谢谢@Didier Dupont。 –

+0

谢谢。一开始对我来说毫无意义,所以我认为它可能值得分享 –

+0

'我相信没有合理的理由这样做,永远'没有理由去做什么?你能否详细说明一下? –