Scala何时需要匿名和扩展函数的参数类型? [英] When does Scala need parameter types for anonymous and expanded functions?

查看:92
本文介绍了Scala何时需要匿名和扩展函数的参数类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Scala编译器何时真正需要匿名函数的参数类型信息?

When does the Scala compiler really need the type information of parameters of anonymous functions?

例如,给定此功能:

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)

我必须指定

callOn(4, (_: Int).toString)

这很丑.为什么我的示例不起作用,而集合类上的map,filter,foldLeft等方法似乎不需要此显式类型?

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?

推荐答案

键入推断的技巧是将其视为迭代优化的过程.每个参数块可用于推断某些类型参数,然后可在后续块中使用这些参数.因此,请遵循以下定义:

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:

def chain[T,A,B](x: T)(fn1: T=>A)(fn2: A=>B) = fn2(fn1(x))

称为:

chain(2)(_*10)("xxx"+_)

那么如何推断呢?首先,我们从块(2)开始,该块已知为类型Int.将其代入T参数,我们得到:

So how is this inferred? First, we start with the block (2) which is known to have the type Int. Substituting that back into the T parameter we get:

def chain[A,B](x: Int)(fn1: Int=>A)(fn2: A=>B) = fn2(fn1(x))

下一个参数块是(_*10),现在我们知道占位符_的类型为Int ...,然后将Int乘以Int得到另一个Int.即使发生溢出,返回类型也是如此.在极端情况下,它可能会引发异常,但是异常的类型为Nothing,它是类型系统中所有其他内容的子类,因此我们仍然可以说Nothing is-an Int和推断的类型Int仍然有效.

The next parameter block is (_*10), where we now know the type of the placeholder _ to be Int... and multiplying an Int by an Int gives another Int. 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 type Nothing which is a subclass of everything else in the type system, so we can still say Nothing is-an Int and the inferred type of Int is still valid.

通过推断A,该方法将变为:

With A inferred, the method becomes:

def chain[B](x: Int)(fn1: Int=>Int)(fn2: Int=>B) = fn2(fn1(x))

仅保留B,可以从("xxx"+_)进行推断.由于String + IntString,所以现在的方法是:

Leaving only B which can be inferred from ("xxx"+_). As String + Int is a String, the method is now:

def chain(x: Int)(fn1: Int=>Int)(fn2: Int=>String) = fn2(fn1(x))

由于该方法的返回类型直接来自fn2,因此为了完整起见,也可以对其进行显式显示:

As the return type of the method comes direct from fn2, that can also be explicitly shown for completeness:

def chain(x: Int)(fn1: Int=>Int)(fn2: Int=>String): String = fn2(fn1(x))

有了它,所有类型都可以安全地解决,并且该方法被证明是静态有效的.

There you have it, all types safely resolved, and the method proven to be statically valid.

在您的情况下,您需要先推断出类型T,然后才能从类型T=>R推断出R.为此,您必须将参数分成两个不同的块,并以咖喱形式编写方法:

In your case, you need the type T to be inferred before it's possible to infer R from the type T=>R. To do this you must split out the parameters into two distinct blocks, writing the method in a curried form:

def callOn[T,R](target: T)(f: (T => R)) = f(target)

这篇关于Scala何时需要匿名和扩展函数的参数类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆