Scala 何时需要匿名函数和扩展函数的参数类型?
Scala编译器什么时候真正需要匿名函数参数的类型信息?
例如,给定这个函数:
def callOn[T,R](target: T, f: (T => R)) = f(target)
那么我不能像这样使用它:
callOn(4, _.toString)
=> error: missing parameter type for expanded function ((x$1) => x$1.toString)
我必须指定
callOn(4, (_: Int).toString)
哪个函数相当难看。为什么我的示例不起作用,而集合类上的 map、filter、foldLeft 等方法似乎不需要这种显式类型?
When does the Scala compiler really need the type information of parameters of anonymous functions?
For instance, given this function:
def callOn[T,R](target: T, f: (T => R)) = f(target)
then I cannot use it like this:
callOn(4, _.toString)
=> error: missing parameter type for expanded function ((x$1) => x$1.toString)
and I have to specify
callOn(4, (_: Int).toString)
which is rather ugly. Why doesn't my example work, whereas method like map, filter, foldLeft, etc. on the collection classes don't seem to need this explicit type?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
类型推理的技巧是将其视为迭代细化的过程。每个参数块可用于推断一些类型参数,然后可在后续块中使用这些参数。因此采用以下定义:
称为:
那么这是如何推断的呢?首先,我们从已知类型为
Int
的块(2)
开始。将其代回T
参数,我们得到:下一个参数块是
(_*10)
,我们现在知道占位符_
的类型code> 为Int
...并将Int
乘以Int
得到另一个Int
。即使发生溢出,返回的类型也是如此;在极端情况下,它可能会抛出异常,但异常的类型为Nothing
,它是类型系统中其他所有内容的子类,因此我们仍然可以说Nothing
是 -Int
并且推断的Int
类型仍然有效。推断出
A
后,方法就变成:只留下可以从
("xxx"+_)
推断出的B
。由于String + Int
是String
,因此该方法现在是:由于该方法的返回类型直接来自
fn2
,因此也可以是为了完整性而明确显示:现在您已经看到了,所有类型都已安全解析,并且该方法被证明是静态有效的。
在您的情况下,您需要先推断出类型
T
,然后才能从类型T=>R
推断出R
。为此,您必须将参数分成两个不同的块,以柯里化形式编写该方法:The trick to type inference is to consider it as an process of iterative refinement. Each parameter block can be used to infer some of the type parameters, which can then be used in subsequent blocks. So take the following definition:
called as:
So how is this inferred? First, we start with the block
(2)
which is known to have the typeInt
. Substituting that back into theT
parameter we get:The next parameter block is
(_*10)
, where we now know the type of the placeholder_
to beInt
... and multiplying anInt
by anInt
gives anotherInt
. This is true of the returned type even if an overflow occurrs; at the extreme end it may throw an exception, but exceptions have the typeNothing
which is a subclass of everything else in the type system, so we can still sayNothing
is-anInt
and the inferred type ofInt
is still valid.With
A
inferred, the method becomes:Leaving only
B
which can be inferred from("xxx"+_)
. AsString + Int
is aString
, the method is now:As the return type of the method comes direct from
fn2
, that can also be explicitly shown for completeness:There you have it, all types safely resolved, and the method proven to be statically valid.
In your case, you need the type
T
to be inferred before it's possible to inferR
from the typeT=>R
. To do this you must split out the parameters into two distinct blocks, writing the method in a curried form:这个问题也在这里得到了解答:
传递所有适用类型的函数
请注意,它确实适用于柯里化版本:
This question has also been answered here:
Passing functions for all applicable types around
Note that it does work with a curried version: