当前位置: 首页 > Scala, 程序代码 > 正文

2020-07-02-Scala语音备忘拾遗 – 4 大括号,柯里化,控制抽象

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程序员可以自己构建控制抽象.

赞 赏

   微信赞赏  支付宝赞赏


本文固定链接: https://www.jack-yin.com/coding/3185.html | 边城网事

该日志由 边城网事 于2020年07月02日发表在 Scala, 程序代码 分类下, 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
原创文章转载请注明: 2020-07-02-Scala语音备忘拾遗 – 4 大括号,柯里化,控制抽象 | 边城网事
【上一篇】
【下一篇】

2020-07-02-Scala语音备忘拾遗 – 4 大括号,柯里化,控制抽象 暂无评论

发表评论

快捷键:Ctrl+Enter