关闭

[Scala]Scala学习笔记八 高阶函数

标签: scala函数高阶函数
393人阅读 评论(0) 收藏 举报
分类:

Scala混合了面向对象和函数式的特性.在函数式编程语言中,函数可以像任何其他数据类型一样被传递和操作.如果想要给算法传入明细动作时,只需要将明细动作包在函数当中作为参数传入即可.

1. 作为值的函数

在Scala中,函数就和数字一样,可以在变量中存放:

import scala.math._

val num = 3.14
val fun = ceil _
println(num) // 3.14
println(fun(num)) // 4.0

上述代码将num设置为3.14,将fun设置为ceil函数.num的类型为Double,fun的类型为(Double) => Double(即接受并返回Double的函数)

备注

ceil函数后的_表示确实指的是ceil这个函数,而不是碰巧忘记了给它传递参数

可以对函数做如下两件事:

  • 调用它
  • 传递它 存放在变量中,或者作为参数传递给另一个函数

Example:

// 调用
fun(num) // 4.0
// 传递
Array(3.14, 2.14, 1.14).map(fun) // Array(4.0, 3.0, 2.0)

备注

map方法接受一个函数参数,将它应用到数组中的所有值,然后返回结果的数组

2. 匿名函数

在Scala中,不需要给每一个函数命名,就像不用给每个数字命名一样:

(x: Double) => 3 * x

上述代码表示该函数将传递给它的参数乘以3.

对与上述匿名函数我们可以如下操作:

(1) 可以将函数存放在变量中:

val triple = (x: Double) => 3 * x
triple(2) // 6.0

上述代码等价于:

def triple(x:Double) = 3 * x

(2) 可以不用命名直接将函数传递给另一个函数:

Array(3.14, 2.14, 1.14).map((x: Double) => 3 * x)

3. 带函数参数的函数

下面是一个接受一个函数作为参数的函数:

def valueAtOneQuarter(fun: (Double) => Double) = fun(0.25)
valueAtOneQuarter(sqrt _) // 0.5 即 sqrt(0.25)

上述函数的参数类型为(Double) => Double,即接受任何Double并返回Double的函数.

4. 参数类型推断

当你将一个匿名函数传递给一个函数时,Scala会尽可能帮助你推断出类型信息.不需要将代码写成如下:

valueAtOneQuarter( (x:Double) => 3 * x ) // 0.75

由于valueAtOneQuarter方法知道你会传入一个类型为(x:Double) => Double的函数,可以将上述代码改为:

valueAtOneQuarter( (x) => 3 * x )
或者
valueAtOneQuarter( x => 3 * x ) // 只有一个参数的函数 可以省略括号

如果参数在=>右侧只出现一次,可以使用_替换,因此进一步改写:

valueAtOneQuarter(3 * _)

5. 柯里化

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

def mul (x: Int, y: Int) = x * y

以下函数接受一个参数,生成另一个接受单个参数的函数:

def mulOneAtATime(x: Int) = (y: Int) => x * y

要计算两个数的乘积,需要调用:

mulOneAtATime(6)(7)

细分说明一下,mulOneAtATime(6)返回的是一个函数(y: Int) => 6 * y.而这个函数又被应用到7,因此最终的结果为42.

Scala支持如下简写来定义柯里化函数:

def mulOneAtATime(x: Int) (y: Int) = x * y

我们可以看到多参数只是个虚饰,不是什么编程语言的特质.

6. 控制抽象

在Scala中,我们可以将一系列语句组成不带参数也没有返回值的函数.如下函数在线程中执行某段代码:

def runInThread(block: ()=>Unit){
  new Thread{
    override def run(){ block() }
  }.start()
}

上述函数为带函数参数的函数,函数参数类型为()=>Unit(表示没有参数也没有返回值).但是如此一来,当你调用该函数时,需要写不美观的()=>:

runInThread{ () => println("Hello");Thread.sleep(10000);println("Bye");  }

要想在调用中省掉()=>,可以使用换名调用表示法:在参数声明和调用该函数参数的地方略去(),但保留=:

def runInThread(block: => Unit){ // (1)
  new Thread{
    override def run() { block } // (2)
  }.start()
}

这样,我们如下调用:

runInThread{ println("Hello");Thread.sleep(10000);println("Bye"); }

Scala程序员可以构建控制抽象:看上去像编程语言的关键字的函数.例如,下面我们定一个until语句,工作原理类似while,只不过把条件反过来用:

def until (condition: => Boolean) (block: => Unit) {
  if(!condition){
    block
    until (condition) (block)
  }
}

使用:

var x = 4
until (x == 0) {
  println(x)
  x = x -1
}
// 4
// 3
// 2
// 1
var x = 0
until (x == 0) {
  println(x)
  x = x -1
}
// 无输出

这样的函数参数有一个专业术语:换名调用参数.和常规的参数不同,函数被调用时,参数表达式不会被求值.毕竟,在调用until时,不希望x == 0被求值得到false.与之相反,表达式成为无参函数的函数体,而该函数被当做参数传递下去. 仔细看一下until函数的定义.注意它是柯里化的:函数首先处理掉condition,然后把block当做完全独立的另一个参数.如果没有柯里化,调用就会变成如下:

until (x == 0, {...})

7. return表达式

在Scala中,不需要使用return语句返回函数值.函数的返回值是函数体的值.不过,可以使用return来从一个匿名函数中返回值给包含这个匿名函数的带名函数.这对于抽象控制是很有用的:

def indexOf(str: String, ch: Char) : Int = {
  var i = 0;
  until (i == str.length){
    if(str(i) == ch) return i
    i += 1
  }
  return -1
}

在这里,匿名函数{ if(str(i) == ch) return i; i += 1 }被传递给until.当return表达式被执行时,包含它的带名函数indexOf终止并返回给定的值.如果要在带名函数中使用return的话,则需要给出其返回类型.例如上例中,编译器没法推断出它会返回Int,因此需要给出返回类型Int.

1
0
查看评论

Scala 之 高阶函数

高阶函数式编程讲解及案例
  • sinat_25306771
  • sinat_25306771
  • 2016-05-22 12:53
  • 2548

Scala入门到精通——第十三节 高阶函数

本节主要内容 高阶函数简介 Scala中的常用高阶函数 SAM转换 函数柯里化 偏函数 1. 高阶函数简介 高阶函数主要有两种:一种是将一个函数当做另外一个函数的参数(即函数参数);另外一种是返回值是函数的函数。这两种在本教程的第五节 函数与闭包中已经有所涉及,这里简单地回顾一下: ...
  • lovehuangjiaju
  • lovehuangjiaju
  • 2015-07-28 09:25
  • 14836

scala 自学笔记 高阶函数

作为值得函数 变量中可以存放函数 import scala.math._ val num = 3.14 // Double val fun = ceil _ // (Double) => Double, fun设为ceil函数, _ 意味着确实指这个函数,而不是碰巧忘记参数。 从技术上讲...
  • escaflone
  • escaflone
  • 2015-02-17 11:15
  • 3353

[Scala函数特性系列]——高阶函数

带函数参数的函数由于是一个接受函数参数的函数,故被称为高阶函数,像之前讲到的map()函数就是高阶函数。如下例所示: 上述代码中,apply函数接受一个函数f作为参数,接受一个Int类型的参数,进行f(v)运算,在下面又给出了f具体的定义(layout函数)。   同样的,高...
  • yhao2014
  • yhao2014
  • 2016-02-21 21:25
  • 2568

!!scala 【经典】一步一步推导!!高阶函数,类型推断

--函数返回函数 scala> def fun1(name1:String) = (name2:String) => println(name1+" "+name2) fun1: (name1: String)String => Unit --等号=左边是函数...
  • gdmzlhj1
  • gdmzlhj1
  • 2016-03-01 14:25
  • 594

Scala 高阶函数

介绍Scala高阶函数及常用的高阶函数。
  • yyywyr
  • yyywyr
  • 2015-12-13 11:36
  • 1026

scala入门-09 scala高阶函数

scala入门-09 scala高阶函数 scala入门-09 scala高阶函数 scala入门-09 scala高阶函数 scala入门-09 scala高阶函数
  • stark_summer
  • stark_summer
  • 2015-01-13 17:36
  • 17033

快学Scala第12章----高阶函数

本章要点 在Scala中函数是“头等公民”,就和数字一样; 你可以创建匿名函数,通常还会把它们交给其他函数; 函数参数可以给出需要稍后执行的行为; 许多集合方法都接受函数参数,将函数应用到集合中的值; 有很多语法上的简写让你以简短且易读的方式表达函数参数; 你可以创建操作代码块的函数,它们看上去就像...
  • u010110208
  • u010110208
  • 2016-06-26 22:42
  • 631

快学Scala习题解答—第十二章 高阶函数

12 高阶函数 12.1 编写函数values(fun:(Int)=>Int,low:Int,high:Int),该函数输出一个集合,对应给定区间内给定函数的输入和输出。比如,values(x=>x*x,-5,5)应该产出一个对偶的集合(-5,25),(-4,16),(-3,9),…,(...
  • u012762573
  • u012762573
  • 2015-08-22 21:52
  • 703

Scala的常用高阶函数

// map: 对传入的每个元素都进行映射,返回一个处理后的元素 Array(1, 2, 3, 4, 5).map(2 * _) // foreach: 对传入的每个元素都进行处理,但是没有返回值 (1 to 9).map("*" * _).foreach(prin...
  • tian_qing_lei
  • tian_qing_lei
  • 2017-09-06 23:23
  • 107
    个人资料
    • 访问:1517576次
    • 积分:22609
    • 等级:
    • 排名:第378名
    • 原创:624篇
    • 转载:133篇
    • 译文:60篇
    • 评论:189条
    博客专栏
    文章分类
    最新评论