类型推断的技巧是将其视为一个迭代细化的过程。每个参数块都可以用来推断一些类型参数,然后可以在后续块中使用。所以采用以下定义:
def chain[T,A,B](x: T)(fn1: T=>A)(fn2: A=>B) = fn2(fn1(x))
称为:
chain(2)(_*10)("xxx"+_)
那么这是如何推断的呢?首先,我们从已知类型为Int 的块(2) 开始。将其代入T 参数,我们得到:
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 和@ 的推断类型987654336@仍然有效。
推断A,方法变为:
def chain[B](x: Int)(fn1: Int=>Int)(fn2: Int=>B) = fn2(fn1(x))
只留下B,可以从("xxx"+_)推断出来。因为String + Int 是String,所以现在的方法是:
def chain(x: Int)(fn1: Int=>Int)(fn2: Int=>String) = fn2(fn1(x))
由于方法的返回类型直接来自fn2,为了完整性,也可以显式显示:
def chain(x: Int)(fn1: Int=>Int)(fn2: Int=>String): String = fn2(fn1(x))
你有它,所有类型都安全解析,并且方法被证明是静态有效的。
在您的情况下,您需要先推断出T 类型,然后才能从T=>R 类型推断出R。为此,您必须将参数分成两个不同的块,以柯里化形式编写方法:
def callOn[T,R](target: T)(f: (T => R)) = f(target)