函数应用程序中未找到隐式参数

5
如果我定义一个只接受数字的打印函数,例如:
def print[T <% Number](value:T) {}
print: [T](value: T)(implicit evidence$1: (T) => java.lang.Number)Unit

我可以使用以下方式调用上述内容:

我可以这样调用:

print(5)
print(5.5)
print(6L) 

但不能使用字符串:

print("aaa")  
<console>:7: error: could not find implicit value for evidence parameter of type (java.lang.String) => java.lang.Number
       print("aaa")

这是预期的结果。

但是如果我将打印函数定义为:

def print2[T <% Number]: T => Unit = value => { } 
print2: [T](implicit evidence$1: (T) => java.lang.Number)(T) => Unit

请注意隐式参数是第一个参数而不是最后一个参数。
如果我尝试手动定义上述函数:
def print3[T](implicit f: (T) => java.lang.Number)(value:T):Unit =  { }  
<console>:1: error: '=' expected but '(' found.
       def print3[T](implicit f: (T) => java.lang.Number)(value:T):Unit =  { }

基本上,上述内容不是一个有效的函数定义,但当我先前定义了print2时,编译器会创建它。
当我使用一个Int调用print2时:
print2(5)
<console>:7: error: type mismatch;
 found   : Int(5)
 required: (?) => java.lang.Number
       print2(5)

如果我将其参数化:

print2[Int](5)
<console>:7: error: type mismatch;
 found   : Int(5)
 required: (Int) => java.lang.Number
       print2[Int](5)

看起来它找不到从scala.Int => java.lang.Integer的隐式转换。

我该如何重新定义print,使其返回函数并以正确的方式访问隐式转换?


你把方法和函数混淆了。请仔细阅读它们的区别。 - Daniel C. Sobral
搜索 Stack Overflow。我在手机上,所以很难查找参考资料。 - Daniel C. Sobral
我认为这可能是“scalac”实现的意外。如果你思考一下,在除了最后位置以外的任何位置使用隐式参数都没有意义。假设允许这样写:def foo(implicit i: Int)(j: Float)(implicit: k: Int)(l: Double) = ...,那么对于应用程序 foo(1)(2)(3) 到底意味着什么?这是不明确的。 - Y.H Wong
我同意。隐式参数应该是最后一个参数。 - ssanj
1个回答

6
这里的问题是你将5作为隐式参数传递。
现在我在电脑上,有一些更正:
def print[T <% Number](value:T) {}

你把它叫做“函数”,但实际上这是一个“方法”。
def print2[T <% Number]: T => Unit = value => { }

再次强调,您称其为函数,实际上它是一个方法,它返回一个函数。该方法接收一个类型参数T和一个隐式参数。

print2(5)

因此,在这里,您调用方法print2并将5作为其隐式参数传递。类型T尚未推断出来,因为它首先尝试使5符合预期的类型T => Number。然而,由于5不符合Function1[T,Number],因此它甚至没有推断T就失败了。
有许多调用print2的方法。例如:
print2(implicitly[Int => Number])
print2[Int]
(print2: Int => Unit)
val f: Int => Unit = print2

然而,要调用由print2返回的函数,您必须避免使(5)看起来像方法print2的隐式参数。实际上,上面只有一个情况需要一些不同的东西:

print2(implicitly[Int => Number])(5)
print2[Int].apply(5)
(print2: Int => Unit)(5)
val f: Int => Unit = print2; f(5)

现在,这些示例中大多数都有显式的类型参数,而不是推断出来的。让我们考虑一下如果没有显式类型参数会发生什么:
print2.apply(5)

因为没有向 print2 传递参数,它会选择符合 T 界限的最具体类型。由于 T 没有界限,因此选择了 Nothing。然后尝试查找隐式的 Nothing => Unit,但是由于不存在这样的隐式,所以失败了。
函数返回值的参数不会被考虑用于类型推断。

我如何调用print2以使用隐式参数? - ssanj
我可以这样调用它:print2(implicitly[Int => java.lang.Number])(5)。这并不是最好的解决方案。 - ssanj
@ssanj,你可以使用print2[Int].apply(5),尽管我意识到那可能不是你想要的。然而,你希望语言以一种它本来不具备的方式工作。 - Daniel C. Sobral

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接