类型推理的技巧是将其视为迭代细化的过程。每个参数块可用于推断一些类型参数,然后可在后续块中使用这些参数。因此采用以下定义:
def chain[T,A,B](x: T)(fn1: T=>A)(fn2: A=>B) = fn2(fn1(x))
称为:
chain(2)(_*10)("xxx"+_)
那么这是如何推断的呢?首先,我们从块开始(2)
已知其类型为Int
。将其代回T
我们得到的参数:
def chain[A,B](x: Int)(fn1: Int=>A)(fn2: A=>B) = fn2(fn1(x))
下一个参数块是(_*10)
,我们现在知道占位符的类型_
to be Int
...并乘以Int
by an Int
给出另一个Int
。即使发生溢出,返回的类型也是如此;在最末端它可能会抛出异常,但异常具有以下类型Nothing
它是类型系统中其他所有内容的子类,所以我们仍然可以说Nothing
is-an Int
和推断的类型Int
仍然有效。
With A
推断,该方法变为:
def chain[B](x: Int)(fn1: Int=>Int)(fn2: Int=>B) = fn2(fn1(x))
只留下B
由此可以推断出("xxx"+_)
. As String + Int
is a 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
在可以推断之前被推断R
从类型T=>R
。为此,您必须将参数分成两个不同的块,以柯里化形式编写方法:
def callOn[T,R](target: T)(f: (T => R)) = f(target)