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

查看:30
本文介绍了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 是-IntInt 的推断类型仍然有效.

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))

只留下可以从("xxx"+_)推断出来的B.由于 String + Int 是一个 String,所以现在的方法是:

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天全站免登陆