我有一个贷款模式,它应用一个函数n次,其中'i'是递增变量。 “偶尔”,我希望传入的函数可以访问'i'....但我不想要求传入的所有函数都要求定义一个param来接受'i'。以下示例......
def withLoaner = (n:Int) => (op:(Int) => String) => {
val result = for(i <- 1 to n) yield op(i)
result.mkString("\n")
}
def bob = (x:Int) => "bob" // don't need access to i. is there a way use () => "bob" instead?
def nums = (x:Int) => x.toString // needs access to i, define i as an input param
println(withLoaner(3)(bob))
println(withLoaner(3)(nums))
答案 0 :(得分:11)
def withLoaner(n: Int) = new {
def apply(op: Int => String) : String = (1 to n).map(op).mkString("\n")
def apply(op: () => String) : String = apply{i: Int => op()}
}
(不确定它与贷款模式的关系)
修改评论中要求的解释很少。
不确定你知道什么,也不知道scala以及你在该代码中没有找到的东西。很抱歉,如果我只是显而易见的话。
首先,scala程序由traits / classes(也是单例对象)和方法组成。所做的一切都是通过方法完成的(将构造函数放在一边)。函数(与方法相对)是各种FunctionN特征(的子类型)的实例(N个参数的数量)。它们中的每一个都具有作为实际实施的应用方法。 如果你写
val inc = {i: Int => i + 1}
它是卑鄙的
val inc = new Function1[Int, Int] {def apply(i: Int) = i + 1}
(定义一个扩展Function1
的匿名类,使用给定的apply方法并创建一个实例)
因此,编写函数比简单方法更重要。此外,您不能重载(具有相同名称的多个方法,不同于签名,正如我上面所做的那样),也不能使用命名参数或参数的默认值。
另一方面,函数是第一个类值(它们可以作为参数传递,作为结果返回)而方法不是。它们会在需要时自动转换为函数,但在执行此操作时可能会出现一些边缘情况。如果方法仅用作函数值,而不是作为方法调用,则编写函数可能更好。
使用f
方法调用函数apply
时使用f(x)
而不是f.apply(x)
(也可以调用),因为scala在函数上使用函数调用符号(值后跟括号和0或更多args)调用方法apply
。 f(x)
是f.apply(x)
的语法糖。这适用于f
的任何类型,它不需要是FunctionN
之一。
在withLoaner中所做的是返回一个对象(匿名类型,但是可以单独定义一个类并返回它的实例)。该对象有两个apply
方法,一个接受Int => String
,另一个接受() => String
。当您withLoaner(n)(f)
时,它意味着withLoaner(n).apply(f)
。如果f
具有其中一个的正确类型,则选择适当的apply方法,否则编译错误。
万一你想知道withLoaner(n)
并不意味着withLoaner.apply(n)
(或者它永远不会停止,那也可能意味着withLoaner.apply.apply(n)
),因为withLoaner是一个方法,而不是一个值。