2019独角兽企业重金招聘Python工程师标准>>>

1.作为值的函数

在Scala中,你可以在变量中存放函数:

import scala.math._val num = 3.14val fun = ceil _

这段代码将num设为3.14, fun设为ceil函数。

说明: ceil函数后的 _ 意味着你确实指的是这个函数,而不是碰巧忘记给它传递参数。 从技术上讲, _ 将ceil方法转成了函数,在Scala中,你无法直接操纵方法,而只能直接操纵函数。

怎么使用函数:

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

以下是如何调用存放在fun中的函数:

fun(num) // fun是一个包含函数的变量,而不是一个固定的函数

以下是如何将fun传递给另一个函数:

Array(3.14, 1.42, 2.0).map(fun) // 将fun传递给另一个函数, Array(4.0, 2.0, 2.0)

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

2.匿名函数

在Scala中,你不需要给每个函数命名,它就是匿名函数:

(x: Double) => 3 * x
// 将这个函数存放在变量中
val triple = (x: Double) => 3 * x
// 这和用def一样
def triple(x: Double) = 3 * x// 作为参数传递
Array(3.14, 1.42, 2.0).map((x: Double) => 3 * x)
Array(3.14, 1.42, 2.0).map((_ * 3) //或者这样,最简形式
Array(3.14, 1.42. 2.0).map{ (x: Double) => 3 * x } // 也可以使用花括号
Array(3.14, 1.42. 2.0) map { (x: Double) => 3 * x } // 使用中置表示法

练习:定义一个函数,入参4个,前两个数Int数字,后两个是函数,当第一个入参大于0时调用第一个函数参数,否则调用第二个函数参数

def call(a:Int, b:Int, f1:(Int,Int)=>Int, f2:(Int,Int)=>Int) = {if(a > 0) f1(a,b) else f2(a,b)
}def add(a:Int, b:Int) = a + b
def sub(a:Int, b:Int) = a - bval f1 = add _
val f2 = sub _//可以采用如下方式调用call函数call(1, 2, f1, f2)
call(1, 2, add _, sub _)
call(1, 2, add, sub)
call(1,2,(a:Int,b:Int)=>a+b,(a:Int,b:Int)=>a-b)

3.带函数参数的函数

def valueAtOneQuarter(f: (Double) => Double) = f(0.25)
valueAtOneQuarter(ceil _) // 1.0
valueAtOneQuarter(sqrt _) // 0.5

这里的参数是一个接受Double并返回Double的函数。而valueAtOneQuarter的函数类型是:

((Double) => Double) => Double ; 一个接受函数参数的函数,它就称作高阶函数。例如valueAtOneQuarter。

高阶函数也可以产出另一个函数,即返回一个函数:

def mulBy(factor: Double) = (x: Double) => factor * x
mulBy(3) // 返回函数 (x: Double) => 3 * x
mulBy函数的威力在于,它可以产出能够乘以任何数额的函数:val quintuple = mulBy(5)
quintuple(20) // 100

mulBy函数的类型为: (Double) => ( (Double) => Double)

4.参数类型推断

Scala有比较强大的参数推导:

def valueAtOneQuarter(f: (Double) => Double) = f(0.25)
valueAtOneQuarter( (x: Double) => 3 * x ) // 0.75
// 可以简单写成
valueAtOneQuarter( (x) => 3 * x ) // 0.75
// 只有一个参数的情况,还可以省却参数的括号:
valueAtOneQuarter( x => 3 * x ) // 0.75
// 如果参数在 => 右侧只出现一次,可以用 _ 替换它
valueAtOneQuarter( 3 * _ ) // 0.75
这些简写方式仅在参数类型已知的情况下有效:val fun = 3 * _ // error
val fun = 3 * (_: Double) // OK
val fun: (Double) => Double = 3 * _ // OK

5.一些有用的高阶函数

(1 to 9).map(0.1 * _) // _应用于所有元素
(1 to 9).map("*" * _).foreach(println _) //打印一个三角形

在这里我们还用到了foreach,它和map很像,只不过他的函数并不返回任何值

filter方法输出所有匹配某个特定条件的元素。

(1 to 9).filter(_ % 2 == 0) // 将能被2整除的过滤出来,输出2,4,6,8

当然,这并不是得到该结果的最高效方式

// reduceLeft方法接受一个二元的函数,将它应用到序列中的所有元素,从左到右
(1 to 9).reduceLeft(_ * _) // 1*2*3*...*8*9

等同于 1*2*3*4*5*6*7*8*9 或者更严格地说 ((((((((1*2)*3)*4)*5)*6)*7)*8)*9)// 排序

"Mary has a little lamb".split(" ").sortWith(_.length < _.length)

6.闭包

函数可以在变量不再处于作用于内时被调用。这样的函数称为闭包, 闭包由代码和代码用到的任何非局部变量定义构成。 例如:

def mulBy(factor: Double) = (x: Double) => factor * x
// 如下调用
val triple = mulBy(3)
val half = mulBy(0.5)
println(triple(14) + " " + half(14)) // 42 7

mulBy首次调用时将参数变量factor设为3, 该变量在(x: Double) => factor * x 函数的函数体内被引用,该函数被存入triple。然后参数变量factor从运行时的栈上被弹出;

mulBy第二次被调用时,参数变量被设为了0.5, 该变量在(x: Double) => factor * x 函数的函数体内被引用,该函数被存入half 。

这样,每一个返回的函数都要自己的factor设置。在这里triple和half存储的函数访问了它们作用于范围外的变量。

7.SAM转换

在Scala中,你可以传递函数作为参数,而在Java中是不可以的(目前),其通常的做法是将动作放在一个实现某接口的类中,然后将该类的一个实例传递给另一个方法。在很多时候,这些接口都只有单个抽象方法(single abstract method), 简称SAM类型。 例如:

var counter = 0val button = new JButton("Increment")
button.addActionListener(new ActionListener {override def actionPerformed(event: ActionEvent) {counter += 1}
})

这里使用了样板代码,我们希望的是只传递一个函数给addActionListener就好了:

button.addActionListener((event: ActionEvent) => counter += 1)

为了启用这个语法,你需要提供一个隐士转换,因为addActionListener是Java的方法。

implicit def makeAction(action: ( (ActionEvent) => Unit ) ) = {new ActionListener {override def actionPerformed(event: ActionEvent) { action(event) }}
}

只需要简单的把这个函数和你的界面代码放在一起就可以在需要传入ActionListener 对象的地方传入任何(ActionEvent) => Unit 类型的函数了。

8.柯里化

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

def mul(x: Int, y: Int) = x * ydef mulOneAtAtime(x: Int) = (y: Int) => x * y // 定一个接受一个参数,生成另一个接受一个参数的函数mulOneAtAtime(6)(7)

这里mulOneAtAtime(6)会返回(y: Int) => 6 * y 类型的函数,然后该函数又被调用,最终计算出结果

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

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

一个典型应用:corresponds方法可以比较两个序列是否在某个条件下相同:

val a = Array("Hello", "World")val b = Array("hello", "world")a.corresponds (b) (_.equalsIgnoreCase(_))

这里corresponds 是一个柯里化的函数,定义:

def corresponds[B] (that: Seq[B]) (p: (A, B) => Boolean): Boolean

that序列和p函数是分开的两个柯里化的参数,类型推断器先推断出that是一个String类型的序列,也就是B是String,然后才能在p函数中推断出函数类型是(String, String) => Boolean。

9.控制抽象

对于一个没有参数也没有返回值的函数:

def runInThread(block: () => Unit) {new Thread {override def run() { block() }}.start()
}runInThread { () => println("Hi"); Thread.sleep(1000); println("Bye") }

() => 这样看上比不那么美观,要向省掉() => 可以使用换名调用表示方法:在参数声明和调用该函数参数的地方略去(),但保留 => :

def runInThread(block: => Unit) {new Thread {override def run() { block } //注意上面省略了(),这里也要省略}.start()
}

在调用时我们可以省略() =>

runInThread { println("Hi"); Thread.sleep(1000); println("Bye") }

在例如:

def until(condition: => Boolean) (block: => Unit) {if (!condition) {blockuntil(condition) (block)}
}var x = 10
until (x == 0) {x -= 1println(x)
}

10.return表达式

在Scala中,函数的返回值就是函数体的值,即最后一个表达式的值。所有不需要使用return语句返回函数值。但是,你可以用return来从一个匿名函数中返回值给包含这个匿名函数的带名函数:

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

如果在带名函数中使用return语句,需要给出它的返回类型。

注:如果异常在被送往待命函数值前,在一个try代码块中被捕获掉了,那么相应的值就不会返回。

转载于:https://my.oschina.net/u/3687664/blog/2236840

Scala学习(十二)高阶函数相关推荐

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

    本节主要内容 高阶函数简介 Scala中的常用高阶函数 SAM转换 函数柯里化 部分应用函数 1. 高阶函数简介 高阶函数主要有两种:一种是将一个函数当做另外一个函数的参数(即函数参数):另外一种是返 ...

  2. python中高阶函数map怎么用_python六十课——高阶函数之map

    1.高阶函数: 特点:函数的形参位置必须接受一个函数对象 分类学习: 1).map(fn,lsd1,[lsd2...]): 参数一:fn --> 函数对象 参数二:lsd1 --> 序列对 ...

  3. Scala编程基础——集合高阶函数

    Scala编程基础--集合&高阶函数 集合 Scala中集合分为可变集合和不可变集合 可变集合:可以修改.添加.移除一个集合的元素. 不可变集合:安全的并发访问. 不可变集合,相比之下,永远不 ...

  4. python学习——函数式编程——高阶函数

    python学习--函数式编程--高阶函数 函数式编程(高阶函数):1:map && reduce; 2 : filter; 3: sorted; ------------------ ...

  5. 【Scala之旅】高阶函数

    本节翻译自 Type Inference Higher-order Functions Nested Methods Multiple Parameter Lists (Currying) 综述:Sc ...

  6. python学习总结1—高阶函数

    python 高阶函数学习 高阶函数 介绍python 高阶函数的使用方法 map/reduce函数 map函数 利用map()函数,把用户输入的不规范的英文名字,变为首字母大写,其他小写的规范名字. ...

  7. Kotlin学习三:高阶函数

    目录 一.高阶函数的基本概念 二.常见高阶函数 1.关于list映射 2.flatMap 3.综合1 4.综合2 三.尾递归优化 四.闭包 五.函数复合 六.科理化 七.偏函数 八.小案例 一.高阶函 ...

  8. Python学习日志10 - 高阶函数和高级应用

    Python学习日志 RBHGO的主页欢迎关注 温馨提示:创作不易,如有转载,注明出处,感谢配合~ 目录 文章目录 Python学习日志 目录 前言 进入正题 Python学习日志10课 - 高阶函数 ...

  9. 【廖雪峰Python学习笔记】高阶函数

    Higher-order function 高阶函数 映射 过滤算法 排序算法 高阶函数 变量可指向函数 >>> abs # 函数 <built-in function abs ...

  10. Python学习之Part09.高阶函数filter(),map(),reduce(),sorted()

    1.高阶函数 一个函数作为参数传给另外一个函数: 一个函数的返回值为另外一个函数(若返回值为该函数本身,则为递归) # abs()用来求一个数的绝对值 # 将abs函数赋值,则f==abs f = a ...

最新文章

  1. html随机播放不同的音乐,如何随机播不同的背景音乐
  2. 把windows一个目录mount到Ubuntu下,非root用户没有写权限
  3. 怎么把ide改成ahci_如何将硬盘由IDE模式修改为AHCI模式,我的主板是华硕P8Z68-VLX,请高手帮帮忙。...
  4. UVa563 - Crimewave
  5. 为什么说数据中心是5G最大的受益者?
  6. Python基础教程:类的property特性
  7. 【C/C++多线程编程之三】创建pthread线程
  8. word 常用快捷键
  9. android 随机布尔值,在 Android 的某些机型,v1.2.2 v1.2.1 加密会导致 boolean 类型的值丢失的问题...
  10. 春天遇见Apache Hadoop
  11. html字体变大自动换行,网页css中实现字符超出宽度自动换行和英语字符不断行的解决方法...
  12. 密码学专题 openssl编译和安装
  13. 【剑指offer】面试题50:第一个只出现一次的字符(java)
  14. 自建Hive数据仓库跨版本迁移到阿里云E-MapReduce
  15. php 扩展 返回字符串,PHP扩展函数返回字符串一定需要使用spprintf吗?
  16. 正则表达式入门教程-连载(2)-正则表达式引擎怎么工作的
  17. CrystalReports2008 SN
  18. 到底什么是NP问题,NP hard问题,NP完全问题?
  19. 批量转移文件,并修改图片的位深度、灰度等信息
  20. mysql远程备份_mysql实现自动远程备份一办法

热门文章

  1. 大文本存mysql怎么建索引_如何正确合理的建立MYSQL数据库索引
  2. win7可以安装sqlserver2008 企业版吗_MYSQLServer2008R2详细的图文安装教程
  3. Effective C#: Item 3: Prefer the is or as Operators to Casts
  4. [yii2] 实现所有action方法之前执行一段代码或者方法
  5. jQuery 筛选
  6. 《Delphi XE6 android 编程入门教程》推荐
  7. RD自身修养 满招损谦受益
  8. ubuntu10.04下audacious2.4源码编译过程(解决2.3cue的bug)
  9. Python—实训day8—掌握DataFrame的常用操作
  10. swift5.给系统类添加便利构造函数