2017-04-24 83 views
0

我有两个隐式转换,添加一个apply方法。斯卡拉隐含def def的参数数量的解析

implicit def f1(foo: Foo) = new { 
    def apply(x: Int) = ??? 
} 

implicit def f2(foo: Foo) = new { 
    def apply(x: Int, y: Int) = ??? 
} 

但我不能使用它们,因为编译器会抱怨不明确的隐式转换

foo(1) // compile error 

为什么会抱怨,如果很清楚哪一个应该被使用?

+0

你有'隐式def f1(foo:Foo)'和'implicit def f2(foo:Foo)'。所以是的,现在还不清楚,即使创建的对象会应用()s具有不同的签名。为什么不把两个apply()放到一个隐式def中呢? – slouc

+0

@slouc因为一个适用于Predef。 – Yaroslav

回答

1

如果问题出在现有的隐含里面Predef,你应该禁用Predef进口这里所描述一样:Override Predef's implicit conversions

例如,让我们尝试做出新apply功能String

scala> implicit def stringToFunction(s: String) = new { 
    | def apply(x1: Int) = ??? 
    | } 
stringToFunction: (s: String)AnyRef{def apply(x1: Int): Nothing} 

scala> "123"(15) 
<console>:13: error: type mismatch; 
found : String("123") 
required: ?{def apply: ?} 
Note that implicit conversions are not applicable because they are ambiguous: 
both method augmentString in object Predef of type (x: String)scala.collection.immutable.StringOps 
and method stringToFunction of type (s: String)AnyRef{def apply(x1: Int): Nothing} 
are possible conversion functions from String("123") to ?{def apply: ?} 
     "123"(15) 
    ^
<console>:13: error: String("123") does not take parameters 
     "123"(15) 
      ^

因此,我们应该从Predef禁用augmentString进口:

scala> import Predef.{augmentString => _, _} 
import Predef.{augmentString=>_, _} 

scala> "123"(15) 
<console>:14: error: type mismatch; 
found : String("123") 
required: ?{def apply: ?} 
Note that implicit conversions are not applicable because they are ambiguous: 
both method wrapString in class LowPriorityImplicits of type (s: String)scala.collection.immutable.WrappedString 
and method stringToFunction of type (s: String)AnyRef{def apply(x1: Int): Nothing} 
are possible conversion functions from String("123") to ?{def apply: ?} 
     "123"(15) 
    ^
<console>:14: error: String("123") does not take parameters 
     "123"(15) 
      ^

让我们禁用wrapString太多,那最终会实现我们想做的事:

scala> import Predef.{augmentString => _, wrapString => _, _} 
import Predef.{augmentString=>_, wrapString=>_, _} 

scala> "123"(15) 
scala.NotImplementedError: an implementation is missing 
    at scala.Predef$.$qmark$qmark$qmark(Predef.scala:284) 
    at $anon$1.apply(<console>:12) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    ... 31 elided 

你可以做在编译器抱怨关于模糊转换后,您的类的隐式转换Foo也是如此。

+0

非常感谢,这工作!我的道歉是成为XY问题的主题。 – Yaroslav

3

您应包括apply()的到一个隐式:

implicit def f1(foo: Foo) = new { 
    def apply(x: Int) = ??? 
    def apply(x: Int, y: Int) = ??? 
} 

http://docs.scala-lang.org/tutorials/tour/implicit-conversions

从类型S为T类型的隐式转换由具有功能类型的隐式值定义S => T,或者通过可转换为该类型值的隐式方法。

所以,你应该有精确一个隐式方法转换Foo工作。

它是如何工作在你的榜样情况:

  1. 编译器看到foo(1)调用。
  2. 它用foo.apply(1)代替它。
  3. 它找到了,该类Foo没有方法apply,并尝试使用此方法找到隐式转换为类。
  4. 它发现两个转换,f1f2,并放弃它。
+0

我无法合并这些含义,导致其中一个出现在'Predef'中。 – Yaroslav

+2

@Yaroslav我想,你应该更新你的问题更具体然后 –

+1

@Yaroslav你使用哪个版本的Scala,你试图隐式转换的'Foo'类是什么? –