一、匿名函数

没有名字的函数就是匿名函数,格式:(x:Int)=>{函数体}

x:表示输入参数类型;Int:表示输入参数类型;函数体:表示具体代码逻辑

传递匿名函数至简原则:

  1. 参数的类型可以省略,会根据形参进行自动的推导;
  2. 类型省略之后,发现只有一个参数,则圆括号可以省略;其他情况:没有参数和参数超过1的永远不能省略圆括号;
  3. 匿名函数如果只有一行,则大括号也可以省略 ;
  4. 如果参数只出现一次,则参数省略且后面参数可以用_代替;
object FunctionTest04 {
def main(args: Array[String]): Unit = {
//将匿名函数传给变量 fun
var fun = (s: String) => {println(s)} //func: String=> Unit 表示传入一个参数为String类型,返回值为Unit类型的函数变量
// f就是一个参数为函数类型,返回值为Unit的普通函数
def f(func: String=> Unit): Unit = {
//表示这个函数参数的默认值
func("Hello,Scala")
}
//这两个意思完全相同
f(fun)
f((s: String) => {println(s)}) //1、匿名函数简化:函数的参数只有一个或者没有,可以省略小括号
//函数体只有一句可以省略大括号
f(s => println(s)) //2、匿名函数简化:当函数的参数只有一个且只出现一次时,该参数的名字可以是任意的名字
//因此,也可以用通配符“_”来表示
f(println(_)) //3、匿名函数简化:如果可以推断出println是函数体,而不是调用的语句,可以直接省略"_"
//注意:小括号必须要省略,否则会认为是调用语句
f(println)
}
}

多个参数的匿名函数应用:

//多参数的匿名函数
def caculator(a: Int,b: Int,op: (Int,Int) => Int):Int = {
op(a,b)
}
//1、标准版
println(caculator(2,3,(x: Int,y: Int) => {x + y}))
//2、省略花括号以及参数类型
println(caculator(2,3,(x,y) => x + y))
//3、由于x,y只出现了一次,故也可以简化
println(caculator(2,3,_ + _))

二、高级函数应用

2.1 函数作为值进行传递

//函数的定义
def fun3():Unit = {
println("定义一个函数")
}
//调用函数
fun3() //函数作为值传递
//这相当于调用一次fun3函数
// var v = fun3()
var v = fun3 //将函数传递给变量的标准形式
var v1: ()=>Unit = fun3
//简化形式, _代表fun3后面的函数体
var v2 = fun3 _

2.2 函数作为参数传递

//定义一个加法函数
def add(a: Int,b: Int): Int = a + b
//这个函数的参数是函数签名(by-name),f表示函数名称,(Int,Int)表示函数的输入类型
//箭头后的Int表示返回类型
//这种方式相当于只传入行为
//函数体中定义了数据
def caculators(f: (Int,Int) => Int):Int = {
f(2,4)
}
//将add作为参数传递给caculators
//如果能推断出不是调用,也可以把 _省略
println(caculators(add _))
println(caculators(add))

2.3 函数作为函数返回值返回

//函数作为返回值返回
def f1() = {
def f2 = {
println("我是f2")
}
//这是f1的返回
f2 _
}
//因为调用f1的返回值是个函数f2,所以变量v3可以继续调用
var v3 = f1()
v3()
//以上两部可以简化为
f1()()

三、阶段练习

object FunctionTest05 {
def main(args: Array[String]): Unit = {
/*
* 练习1:定义一个匿名函数,并将它作为值赋给变量fun。函数有三个参数,类型分别为Int,String,Char,返回值类型为Boolean。
* 要求调用函数fun(0, “”, ‘0’)得到返回值为false,其它情况均返回true。
* */
var fun = (i: Int,s: String,c: Char) =>{
if (i == 0 && s == "" && c == '0')
{
println("false")
return false
}else{
println("true")
return true
}
}
fun(0,"",'0')
/*
* 练习2: 定义一个函数func,它接收一个Int类型的参数,返回一个函数(记作f1)。
* 它返回的函数f1,接收一个String类型的参数,同样返回一个函数(记作f2)。
* 函数f2接收一个Char类型的参数,返回一个Boolean的值。
* 要求调用函数func(0) (“”) (‘0’)得到返回值为false,其它情况均返回true。
* */
def func (i:Int) = {
def f1(s: String) = {
def f2(c: Char): Boolean = {
if (i == 0 && s == "" && c == '0')
{
println("false")
return false
}else{
println("true")
return true
}
}
//返回函数 f2
f2 _
}
//返回函数f1
f1 _
}
func(0)("")('0')
}
}
/*
* 模拟Map映射、Filter过滤、Reduce聚合
* */
//1、模拟Map映射
//array 代表传入数据
//op 代表传入的操作函数
def Map(array: Array[Int], op: Int => Int): Array[Int] = {
// 遍历数组并将返回值elem传递给函数 op
for (elem <- array) yield op(elem)
} //定义数组
var arr: Array[Int] = Array(10,20,30,40)
//定义操作:数据加1
def addOne(i: Int):Int = i+1 //调用Map函数
// Map(arr,addOne) 返回的是一个引用类型,需要使用mkString方法
println(Map(arr,addOne).mkString(","))
}

输出:11,21,31,41
//接上面代码,简化操作
//例如:所有元素乘2
var arr2 = Map(Array(10,20,30,40),_ * 2)
println(arr2.mkString(","))
输出:20,40,60,80
def main(args: Array[String]): Unit = {
//2、模拟Filter过滤
def Filter(array: Array[Int], op:Int => Boolean) = {
//需要导入ArrayBuffer类
var arr: ArrayBuffer[Int] = new ArrayBuffer[Int]()
//循环判断
for (elem <- array if op(elem)){
arr.append(elem)
}
arr.toArray
}
//排除数组中的偶数
var arr1 = Filter(Array(1,2,3,4,5,6), _ % 2 == 1)
//打印输出
println(arr1.mkString(","))
}
def main(args: Array[String]): Unit = {
//3、模拟Reduce聚合操作
def Reduce(array: Array[Int],op: (Int,Int) => Int) = {
//获取输入的数组的第一个值
var init: Int = array(0)
//循环遍历数组,左闭又开区间
for (elem <- 1 until array.length ){
//执行对应的操作
init = op(init,array(elem))
}
//返回 Init
init
}
//输入数组以及累加操作
println(Reduce(Array(1,2,3,4),_ + _)) }

四、函数柯里化&闭包

闭包:函数式编程的标配 ,如果一个函数,访问到了它的外部变量的值,那么这个函数和他所处的环境,称为闭包 ;

函数柯里化:把一个参数列表的多个参数,变成多个参数列表。

def main(args: Array[String]): Unit = {
/*
* 函数闭包&柯里化
* */
//1、闭包代码示例
def f1()={
var v:Int = 3;
//函数f2用到了函数外的变量v,此时f2就是一个闭包的环境
def f2(a: Int) = {
v + a
}
} //2、柯里化示例
def add(a: Int,b: Int) = {
a + b
}
//变为如下形式,就是柯里化
def addCur(a: Int)(b: Int) = a + b
//具体实现过程是,先演变为:
//实际就是函数add1中嵌套了一个匿名函数: (b: Int) => a + b
def add1 (a: Int) = (b: Int) => a + b }

五、递归

注意:在Scala的递归中,必须声明函数返回值类型

 def main(args: Array[String]): Unit = {
test(5)
}
def test(i: Int):Int = {
if (i == 1) return 1
else {
i * test(i - 1)
}
}

六、控制抽象

Scala的解释器在解析函数参数(function arguments)时有两种方式:

  1. 传值调用:先计算参数表达式的值,再应用到函数内部;
  2. 传名调用:将未计算的参数表达式直接应用到函数内部。

注意:Java只有值调用;Scala既有值调用,又有名调用。

def main(args: Array[String]): Unit = {
//传名调用示例:
delayed(time())
}
def time() = {
println("时间:")
System.nanoTime()
}
def delayed(t: => Long) = {
println("参数:" + t)
}

七、惰性加载

当函数返回值被声明为lazy时,函数的执行将被推迟,直到我们首次对此取值,该函数才会执行。这种函数我们称之为惰性函数。

def main(args: Array[String]): Unit = {
//注意:这里只能声明为常量val
lazy val v = sum(2,3)
println("----------------------")
println("v=" + v)
}
def sum(a: Int,b: Int) = {
println("sum 被执行了")
a + b
} 输出:
----------------------
sum 被执行了
v=5

Scala函数高级篇的更多相关文章

  1. Scala函数高级操作

    字符串高级操作:***** 非常重要 将函数赋值给变量/值def sayHello(name:String): Unit = { println(s"Hello:$name")} ...

  2. scala函数进阶篇

    1.求值策略scala里有两种求值策略Call By Value -先对函数实参求值,在函数体中用这个求出的参数值.Call By Name -先不对函数实参求值,而是函数实参每次在函数体内被用到时都 ...

  3. Scala学习——函数高级操作

    scala函数高级操作 一.字符串高级操作 多行字符串和插值 package top.ruandb.scala.Course06 object StringApp { def main(args: A ...

  4. Scala进阶之路-Scala函数篇详解

    Scala进阶之路-Scala函数篇详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.传值调用和传名调用 /* @author :yinzhengjie Blog:http: ...

  5. Kotlin——高级篇(二):高阶函数详解与标准的高阶函数使用

    在上面一个章节中,详细的讲解了Kotlin中关于Lambda表达式的语法以及运用,如果还您对其还不甚理解,请参见Kotlin--高级篇(一):Lambda表达式详解.在这篇文章中,多次提到了Kotli ...

  6. Kotlin——从无到有系列之高级篇(一):Lambda表达式

    如果您对Kotlin很有兴趣,或者很想学好这门语言,可以关注我的掘金,或者进入我的QQ群大家一起学习.进步. 欢迎各位大佬进群共同研究.探索 QQ群号:497071402 进入正题 经过前面一系列对K ...

  7. ORM查询语言(OQL)简介--高级篇(续):庐山真貌

    相关文章内容索引: ORM查询语言(OQL)简介--概念篇 ORM查询语言(OQL)简介--实例篇 ORM查询语言(OQL)简介--高级篇:脱胎换骨 ORM查询语言(OQL)简介--高级篇(续):庐山 ...

  8. 25个增强iOS应用程序性能的提示和技巧(高级篇)(2)

    25个增强iOS应用程序性能的提示和技巧(高级篇)(2) 2013-04-16 14:56 破船之家 beyondvincent 字号:T | T 在开发iOS应用程序时,让程序具有良好的性能是非常关 ...

  9. PHP笔记(PHP高级篇)

    高级篇中将涉及数据库的使用以及Cookie和Session会话,提高PHP的开发效率和运行效率 PHP程序员需要掌握的MySQL操作 为项目设计表 使用SQL语句 MySQL的目录结构 data目录中 ...

随机推荐

  1. 『无为则无心』Python函数 — 31、命名空间(namespace)

    目录 1.什么是命名空间 2.三种命名空间 3.命名空间查找顺序 4.命名空间的生命周期 5.如何获取当前的命名空间 1.什么是命名空间 命名空间指的是变量存储的位置,每一个变量都需要存储到指定的命名 ...

  2. 初识python: 类练习 - 老板&员工

    需求: 1.员工具有姓名.年龄.能力值(能力值为100-年龄),可以工作,每工作一次,该员工的能力值-5,创建__str__方法,打印该员工的信息: 2.老板具有投资金额,工作量,员工列表.可以雇佣员 ...

  3. python pathlib模块(面向对象的文件系统路径)

    该模块提供表示文件系统路径的类,其语义适用于不同的操作系统 导入Path类: 获取当前目录的绝对路径: 返回当前目录的路径对象 路径拼接 os与PurePath/Path函数映射表 来自为知笔记(Wi ...

  4. 初识python 之 爬虫:爬取某网站的壁纸图片

    用到的主要知识点:requests.get 获取网页HTMLetree.HTML 使用lxml解析器解析网页xpath 使用xpath获取网页标签信息.图片地址request.urlretrieve ...

  5. tomcat 可部署4种方式

    1.在conf\Catalina\localhost 目录下添加.xml配置文件 2.修改server.xml文件进行部署 3.将项目拷贝到webapps目录下 4.启动tomcat后,打开tomca ...

  6. tomcat启动卡在了 At least one JAR was scanned for TLDs yet contained no TLDs 的根本原因与解决办法

    1.前言 有时候服务器开启时启动不了,卡在了 org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned fo ...

  7. 新增访客数量MR统计之数据库准备

    关注公众号:分享电脑学习回复"百度云盘" 可以免费获取所有学习文档的代码(不定期更新)云盘目录说明:tools目录是安装包res 目录是每一个课件对应的代码和资源等doc 目录是一 ...

  8. YBT 1633:【例 3】Sumdiv

    http://ybt.ssoier.cn:8088/problem_show.php?pid=1633 A^B 快速幂求结果,所有约数和,可以通过组合来进行得到. 技巧,通过递归得到1~n次的和.su ...

  9. fis学习

    http://fis.baidu.com/docs/beginning/getting-started.html#md5 还是喜欢时间戳?没问题,FIS也可以满足你的需求,点击这里

  10. Protobuf使用--go和C#

    一.Go安装及使用protobuf工具 以下都是基于Linux系统: 1.安装 A) protobuf 编译工具安装 1.下载 protoBuf: cd $GOPATH/src/ git clone ...