一、匿名函数

没有名字的函数就是匿名函数,格式:(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. html基础 表单标签 input系列 以及优化方法

    场景:在网页中显示手机用户信息的表单效果. 如:登录页.注册页标签名:input 用法是通过改变type属性值,来展示不同效果 1.1 html 代码 <!--placeholder 提示符又叫 ...

  2. CentOS7找不到ifconfig命令解决方法

    CentOS默认支持使用ip a命令查看网卡信息,但我们更习惯用ifconfig查看网卡信息,但在CentOS使用该命令会提示找不到命令,可以用如下方法解决问题. 1.使用yum search ifc ...

  3. nginx安装,手动源码安装

    什么是Nginx? Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务.Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Ra ...

  4. 校招——面试(Android岗)总结

    PS:持续更新,未完待续 2016.8.24某为面试 自我介绍一下 链表和数组的区别 数组的存储空间是静态.连续分布的,初始化过大会造成空间浪费,过小会使空间溢出:链表的存储空间是动态分布的,只要内存 ...

  5. 微服务架构 | 3.2 Alibaba Nacos 注册中心

    目录 前言 1. Nacos 基础知识 1.1 Nacos 命名方式 1.2 Nasoc 是什么 1.3 Nacos 的 4 个关键特性 1.4 Nacos 生态图 1.5 Nacos 架构图 1.6 ...

  6. java(基于springboot项目或maven项目均可) 操作mongodb

    一.引入mongodb 坐标依赖<dependency> <groupId>org.mongodb</groupId> <artifactId>mong ...

  7. actf2020upload

    actf2020upload .php后缀过滤 1.上传文件,要求后缀为.png/.gif/.jpg 2.抓包,后缀改成.phtml后放行,上传成功,访问地址,根目录下找到flag

  8. 微服务架构 | 12.1 使用 Apache Dubbo 实现远程通信

    目录 前言 1. Dubbo 基础知识 1.1 Dubbo 是什么 1.2 Dubbo 的架构图 1.3 Spring Cloud 与 Dubbo 的区别 1.4 Dubbo 的特点 1.5 Dubb ...

  9. 关于3G移动通信网络中用户ip的配置过程的研究(中国电信cdma2000)

    在RP口对ppp过程进行研究 PPP协商过程,如下图所示: 在建立ppp过程中pdsn需要与FAAA.HAAA交互.同时在分组数据业务进行过程中这种交互更加频繁,介绍如下,分为两种情况,简单ip,移动 ...

  10. pytest文档4-fixture之conftest.py

    用例1需要先登录,用例2不需要登录,用例3需要先登录.很显然这就无法用setup和teardown来实现了.fixture之conftest.py就是自定义测试用例的预置条件 1.firture相对于 ...