2020-07-02-Scala语音备忘拾遗 – 4 大括号,柯里化,控制抽象
Jul022020
2020-07-02-Scala语音备忘拾遗 – 4 大括号,柯里化,控制抽象
Scala提供了一些语法糖,在函数调用时可以省略小括号,或者使用大括号替代小括号,看似简单的用法,如果不理清楚了,容易误用,阅读源码也会变得困难.
柯里化和控制抽象使用了相关的大括号语法糖,一并整理记录,以备忘.
1. 方法调用时的大括号和小括号一些原则
- obj.func(p)的调用方式可以写成 obj func p,例如
print("hello world" substring(0, 3) toUpperCase() indexOf "h")
- 当调用的方法只有一个参数时,可以使用大括号代替小括号,比如
print {"hello world"}
- 小括号可以括起来一个表达式,其值也是这个表达式的值,
- 大括号可以括起来多个表达式,表示代码块,代码块的值时其中最后一个表达式的值
- 如果需要,可以使用代码块(大括号括起来)生成函数
- 单行(单表达式)代码块可以省略大括号,但case子句除外
- 以代码块为参数的函数调用中可以省略小括号
package com.jack.yin
class TestBracketP {
def testBracketP(generator: (Int ,Int) => Int ) :Unit = {
val x = 1
val y = 2
println( s"generator(x,y) = ${generator(x,y)}" )
}
}
object TestBracketP{
def main(args: Array[String]): Unit = {
val instance = new TestBracketP()
// 使用代码块生成函数 { (x, y) => {x + y} }
instance.testBracketP( { (x, y) => {x + y} } ) // 1. 正统的调用方式,啰嗦
instance.testBracketP { { (x, y) => {x + y} } } // 2. 当调用的方法只有一个参数时,可以使用大括号代替小括号,啰嗦
instance.testBracketP ( (x, y) => {x + y} )// 3. 基于 1 简化, 单表达式 代码块,省略了 大括号
instance.testBracketP ( (x, y) => x + y )// 4, 基于 3 更进一步简化, 单表达式 代码块,省略了 大括号括号
instance.testBracketP( { (a, b) => { println(s"a + b = ${a + b}"); a * b} } ) // 正统的调用方式,啰嗦,注意这里代码块中有两个表达式(语句)
instance.testBracketP( (a, b) => { println(s"a + b = ${a + b}"); a * b} ) // (a, b) => { println(s"a + b = ${a + b}"); a * b} 看成单表达式,生成一个函数,可以省略外部的大括号
instance.testBracketP { (a, b) => { println(s"a + b = ${a + b}"); a * b} } // 以代码块为参数调用时,省略了外部的小括号
instance.testBracketP { (a, b) => println(s"a + b = ${a + b}"); a + b } // 可进一步简化
val tupleList = List[(String, String)]()
// 不能编译
//val filtered = tupleList.takeWhile( case (s1, s2) => s1 == s2 ) // 单行语句, 代码块中使用case语句生成一个偏函数实例,作为参数时不能省略大括号
// i.e. tupleList.takeWhile({ case (s1, s2) => s1 == s2 })
val filtered = tupleList.takeWhile{ case (s1, s2) => s1 == s2 } // 代码块生成偏函数作为参数,省略了函数调用的小括号
}
}
2. 柯里化
正常情况下,一个方法只有一个参数列表,包含0,1或者多个参数.
方法也可以定义多个参数列表,当使用较少的参数列表调用多参数列表的方法时,会产生一个新的函数,该函数接收剩余的参数列表作为其参数。这被称为柯里化。
参考这里
package com.jack.yin
class Test {
//正常方法定义
def plainOldSum(x: Int, y: Int) = x + y
//柯里化定义,当时用 curriedSum(1)_ 时返回的时一个函数引用,该函数接受第二个参数列表中的参数y
def curriedSum(x: Int)(y: Int) = x + y
}
object Test {
def main(args: Array[String]): Unit = {
val instance = new Test()
val addOne = instance.curriedSum(1)_
print(addOne(2))
}
}
3. 控制抽象
假如你有下面的函数(注意:这里使用了传名调用
特性,参考这里)
def until(condition: => Boolean)(block: => Unit) {
if(!condition){
block
until(condition)(block)
}
}
由上文所述可知,函数until是柯里化的,调用时,可以采用下面的简化方式
var x = 10
until (x == 0) {
x -= 1
println(x)
}
代码中 x == 0
是单行代码块,省略了包裹它的大括号,(x == 0)后面大括号括起来的部分,是多行代码块,因为until的第二个参数列表中只有一个参数,
调用时省略了小括号.
上面对函数until的调用,看起来就像until是scala的内建的关键字一样(像不像if,do,while, …?),表明scala程序员可以自己构建控制抽象
.
微信赞赏 支付宝赞赏