JAVA程序员的scala笔记 - 函数

函数字面量

所谓函数字面量,就是用一个表达式来表示函数本身,区别于Java中的方法只能定义在类中,我们可以在任何地方定义函数字面量(类似于JavaScript),我们可以将函数字面量赋值给某个变量。或者在某个需要函数作为参数的地方,将函数字面量直接作为参数传递给函数(lambada表达式)。函数字面量或者将这种方式叫做匿名函数?。
在scala中,通常将在对象中定义的跟对象相关的函数叫做方法(method),在其它地方定义的函数叫做函数。在有些地方,他们通常混用,也不会有多大的影响。
以下是函数字面量和函数作为参数传递的示例

object TestFunc {

  // (a: Int, b: Int) => a + b 是一个函数字面量,
  // 将这个函数赋值给func变量
  val func = (a: Int, b: Int) => a + b

  // 将一个函数赋值给另外一个函数
  val funcB = func

  // 使用函数的变量调用函数
  func(3, 5)

  // 调用方法,并在某个需要传入函数作为参数的地方,传入字面量
  getResult(3, 5, (a, b) => a * b)

  // 定义一个方法,方法接受三个参数,前两个参数为两个数字,后面是一个函数,
  // 这个方法用于获取两个参数通过指定计算函数计算之后,得到的值
  // 这个示例没有什么作用,仅仅展示一种语法方式
  def getResult(num1: Int, num2: Int, func: (Int, Int) => Int) = {
    func(num1, num2)
  }
}

局部函数

局部函数是指在某个函数或者方法内部定义函数。
在函数式编程中,程序应该被翻译成很多小的函数,这些小的函数可能只在某个函数中被定义和调用。在java中,只能定义私有方法。在Scala中可以定义局部函数(就像JavaScript)。
下面是在main方法中定义函数并调用的例子

  def main(args: Array[String]): Unit = {
    // 使用def定义局部函数
    def func(a: Int, b: Int) = a + b

    // 使用函数字面量定义函数并将之赋值给某个变量
    val func1 = (a: Int, b: Int) => a + b

    // 调用局部函数
    func(4, 8)
    func1(3, 5)
  }

占位符语法

在定义函数字面量(不是通过def定义函数),为了语法简洁,可以使用占位符语法来表示一个函数

// 使用 _ 作为占位符来定义函数,_分别表示传入的第一个函数和第二个函数
val func2 = (_: Int) + (_: Int)
// 这个函数的定义和上面的函数的定义是等价的
val func3 = (a: Int, b: Int) => a + b

// 在需要一个函数作为参数传入时,使用占位符语法,使用上面的getResult函数
// 第三个参数是一个函数
getResult(3, 5, (a, b) => a * b)
 // 使用占位符语法传入参数,_*_看起来像一个表达式,但其实是一个函数
getResult(3, 5, _ * _)
// 参数在函数体中被引用两次,不能使用占位符语法
val func4 = (a: Int, b: Int) => a * b + (a + b)

在使用占位符语法是,函数的参数会按照顺序依次替换_作为实际参数进行计算
在使用占位符时要注意,占位符出现的次数必须等于函数参数的个数,而且第N个占位符的值也是参数列表中第N个参数的值。如果某个函数的参数会在函数中被引用两次,则不能使用占位符语法。

可变参数

在函数定义中,可以将函数最后一个参数设置为可变数量(和JAVA中的可变参数有一点区别)

// 使用 * 定义可变参数的函数
def func5(args: Int*) = {
  // args在函数内部表现为一个数组
  println(args.length)
  for (arg <- args) {
    println(arg)
  }
}
// 调用可变参数的函数
func5(6)
func5(1, 2)
func5(1, 2, 3, 4, 5)

// 如果我们已经有一个数组,并且打算将它做为参数传递给不定参数的函数时,需要使用 _* 语法
val arr = Array(7, 8, 9, 0)
// 表示传入的参数会被转换为不定参数
func5(arr: _*)
// 表示传入的参数是数组,编译不会通过
func5(arr)

在java中,如果最后一个参数是可变参数,我们可以向最后一个参数传入一个数组表示所有的参数,但这在scala中是不允许的。如果我们已经有一个数组,并且打算将它做为参数传递给不定参数的函数时,需要使用 _* 语法

参数的按名传递和参数默认值

在通常情况下,在调用函数时,参数是按照在实参列表中的位置进行传递的,在scala中,可以按名称传递参数。按名称传递时,参数的顺序不影响结果

def tf(a: Int, b: Int) = {
  println(s"a=$a")
  println(s"b=$b")
}
// 按位置传递参数 a=12,b=16
tf(12, 16)
tf(16, 12)
// 按名称传递参数,参数的位置不影响结果
tf(a = 12, b = 16)
tf(b = 16, a = 12)

我么可以在定义函数时,指定某些参数的默认值,在调用函数时,可以省略该参数,通常和按名称传递参数一起使用

// 定义一个带默认值的参数
def nor(a: Int = 0, b: Int = 12) = {
  println(s"a=$a,b=$b")
}
// 均使用默认值
// a=0,b=12
nor()

// 按位置传递参数,第一个参数被覆盖
// a=1,b=12
nor(1)

// 按位置传递参数,并且想改写第二个参数,第一个参数不能省略
// a=1,b=100
nor(1, 100)

// 按名称传递参数,可以省略参数
// a=1,b=100
nor(b = 100)

柯里化

柯里化(Currying)指的是将原来接受两个参数的函数变成新的接受一个参数的函数的过程。新的函数返回一个以原有第二个参数为参数的函数。

实例
首先我们定义一个函数:

def add(x:Int,y:Int)=x+y

那么我们应用的时候,应该是这样用:add(1,2)

现在我们把这个函数变一下形:

def add(x:Int)(y:Int) = x + y

那么我们应用的时候,应该是这样用:add(1)(2),最后结果都一样是3,这种方式(过程)就叫柯里化。

柯里化的意义。
当我们将函数作为参数传入时,可以实现一种新的控制结构,如下所示。

import java.io.PrintWriter

object TestApp {
  // 定义一个柯里化函数,向指定路径写入文件,并关闭流
  def withPrintWriter(path: String)(func: PrintWriter => Unit) = {
    val writer = new PrintWriter(path)
    try {
      func(writer)
    } finally {
      writer.close()
    }
  }

  def main(args: Array[String]): Unit = {
    withPrintWriter("d:/out.txt") {
      printer => {
        printer.println("good good study")
      }
    }
  }
}

学习笔记

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342