我遇到了一个看起来像这样的函数:
def doSomethingQuestionable(config: someConfig, value: String)(default: => String) : String
有趣的是作为第二个参数组传入的无参数函数。在代码库中,该方法仅使用config和两个字符串调用,后者是一些默认值,但是作为String而不是函数。在方法的代码体内,default被传递给一个带有3个字符串参数的方法。所以功能"默认"只能解析为此方法体内的字符串。
除了在我正在经历的代码库中使用此方法不会发生的currying使用时,是否有任何好处,以这种方式定义方法?为什么不在一个参数组中用3个字符串参数定义它?
我错过了什么?这里有一些编译优势?请记住,我假设不会对此进行任何干扰,因为它是一个很大的代码库,并且目前还没有使用此方法。
答案 0 :(得分:2)
关键是要有一个可能很昂贵的默认字符串,只有在需要时才会创建。你编写代码就像创建要传入的字符串一样,但是因为它是一个名字参数('=> String'),它实际上会变成一个函数,只要default
就会被透明地调用在doSomethingQuestionable
方法中引用。
保持分开的原因是你需要一大块代码来创建该字符串。如果你永远不会做,也永远不会,也可能是
def doSomethingQuestionable(config: someConfig, value: String, default: => String): String
但是,如果你这样做,
def doSomethingQuestionable(cfg, v){
// Oh boy, something went wrong
// First we need to check if we have a database accessible
...
// (Much pain ensues)
result
}
比在多参数参数列表中嵌入代码块作为一个参数更好。
答案 1 :(得分:1)
这是一个无参数函数,返回String
:
() => String
这不是你拥有的。 此,
=> <WHATEVER>
是按名称而不是按值传递的参数。例如:
=> String // A string being passed by-name
=> () => String // A parameterless function returning string being passed by-name
这些模式之间的区别在于,在按值时,参数评估并且生成的值被传递,而在按名称时,参数是按“原样”传递,并在每次使用时进行评估。
例如:
var x = 0
def printValue(y: Int) = println(s"I got $y. Repeating: $y.")
def printName(y: => Int) = println(s"I got $y. Repeating: $y.")
printValue { x += 1; x } // I got 1. Repeating: 1.
printName { x += 1; x } // I got 2. Repeating: 3.
现在,至于为什么方法将其分成第二个参数,这只是句法愉悦的问题。例如,采用类似定义的方法foldLeft
。你可以这样写:
(1 to 10).foldLeft(0) { (acc, x) =>
println(s"Accumulator: $acc\tx: $x\tacc+x: ${acc+x}")
acc+x
}
如果foldLeft
被定义为单个参数列表,它将如下所示:
(1 to 10).foldLeft(0, { (acc, x) =>
println(s"Accumulator: $acc\tx: $x\tacc+x: ${acc+x}")
acc+x
})
没有太大的不同,被授予,但看起来更糟糕。我的意思是,你不要在下面写这个东西,是吗?
if (x == y, {
println("Same thing")
}, {
println("Different thing"
})