scala高级函数快速掌握
scala高级函数
- 一.函数至简原则
- 二.匿名的简化原则
- 三.高阶函数
- 四.柯里化和闭包
- 五.递归
- 六.抽象控制
- 七.惰性加载
🔥函数对于scala(函数式编程语言)来说非常重要,大家一定要学明白,加油!!!!🔥
一.函数至简原则
1.return可以省略,Scala会把函数体最后一行代码作为返回值
def f0(name:String):String ={name}println(f0("scala"))
2.如果函数体内只有一行代码,可以省略花括号
def f2(name:String):String=name
3.如果返回值类型如果能推断出来,:和返回值类型可以一起省略
def f3(name:String)=name
这不就相当于数学上的函数嘛! f(x)=x。 这也是至简原则的目的,让函数最终尽可能符合我们数学上的使用习惯。
4.如果return没有省略,则返回值类型不能省略
def f4(name:String)={return name}
//会报错
5.如果函数声明Unit(空类型),那么即使函数体中使用return也不起作用
def f5(name:String):Unit={return name}
6.scala如果期望是无返回值类型,可以省略等号,这种函数也叫做过程,不存在映射关系
def f6(name:String){println(name)}
7.如果函数无参数,但是声明了参数列表,那么调用时,小括号,可加可不加
def f7():Unit={println(name)}
f7()
f7
8.如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略
def f8:Unit={println(name)}
f8
9.如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略,也不需要返回值。也就是匿名函数!lambda表达式
(name:String) =>{println(name)}
lambda表达式没有函数名如何调用呢?
用法1:直接定义个变量,这样就相当于有了名字
val fun =(name:String) =>{println(name)} //lambda表达式的返回值(函数类型)赋给fun 相当于有了名字
fun("scala")
用法2:定义一个函数,以函数作为参数传入
//相当于函数的参数是固定的,这个函数的操作却决于传入的函数
val fun =(name:String) =>{println(name)}
def f(func:String =>Unit):Unit={ //String =>Unit 是函数的类型,代表函数的参数是String类型,返回类型是Unitfunc("scala")
}
f(fun)
f((name:String) =>{println(name)})
匿名函数就是一个表达式,它的返回值也就是这个表达式的值。
二.匿名的简化原则
1.参数类型可以省略,会根据形参进行自动推导
f((name) =>{println(name)}) //看用法2中定义的函数,传入的参数已经定义死了,必须是String =>Unit(String类型)
2.类型省略之后,如果只有一个参数,圆括号可以省略.
f(name=>{println(name)})
3.匿名函数如果只有一行,大括号也可以省略
f(name=>println(name))
4.如果参数只出现一次,则参数省略且后面可以用_代替,注意对应顺序
f(println(_))
5.如果可以推断出,当前传入的println是一个函数体,而不是调用语句,可以直接省略下划线
f(println) //传入的是一个操作
案例:定义一个“二元运算”函数,只对1和2两个数操作,但是具体的运算通过传入的参数决定
def dualFunction(fun:(Int,Int)=>Int):Int={fun(1,2) //具体的参数已经是定死的
}
val add = (a:Int,b:Int)=>a+b
val minus = (a:Int,b:Int)=>a-b
println(dualFunction(add))
println(dualFunction(minus))
println(dualFunction((a,b)=>a-b))
println(dualFunction(_-_))
三.高阶函数
函数在scala编程里面是一等公民,不想Java只能在类里面定义方法,非常灵活,在一个代码块中就可以定义函数,调用函数。
1.函数可以作为值进行传递,类似给函数起别名
def f(n:Int):Int={println("f调用")n+1
}
val f1 = f _ //f _ 代表f这整个函数体
val f2:Int=>Int =f //这样f1(函数对象)就是函数类型(f2:Int=>Int),编译器知道要传函数,所以可以只写个f
2.函数作为参数进行传递
这里就是匿名函数案例演示的那种,参数是定义死的,具体操作看传入的函数(参数)
但是数据一定要定义死嘛?我们可以函数参数和数据参数一起传入
def dualEval(op:(Int,Int)=>Int,a:Int,b:Int):Int={op(a,b)
}
def add(a:Int,b:Int):Int={a+b
}
println(dualEval(add,12,35)) //把普通函数作为参数
3.函数作为函数的返回值返回
看到这里我们可以发现,只要是值用到的地方,我们都可以用函数进行代替。
这里就设计到函数嵌套了
def f5():Int => Unit{ //Int => Unit这里说明返回值是函数类型def f6(a:Int)={println("f6调用"+6)}f6 //return 可以省略
}
println(f5()) //这里得到的是一个引用(函数),也就是得到的f6()
println(f5()(25))
**应用案例:**对数组进行处理,将操作抽象出来,处理完毕之后的结果返回一个新的数组。(也就是大数据map操作)
yield:就是在for循环中,每次循环都会产生一个值,然后将每次产生的值保存,最后组成一个集合。
val arr:Array[Int]=Array(12,45,75,98) //每次只对数组中的一个元素进行操作,这个操作是单独抽象的,只需要单独的定义操作def arrayOperations(array: Array[Int],op:Int=>Int):Array[Int]={for (elem <- array) yield op(elem)}//定义一个加1操作def addOne(elem:Int):Int={elem+1}//调用函数var newArray:Array[Int]=arrayOperations(arr,addOne)println(newArray.mkString(","))//这里传入匿名函数也是可以的
var newArray2 = arrayOperations(arr,_+1 )
这里的应用是以后处理大数据,来了一堆集合,数据就是那些,但是需要进行很多步操作, 我们通过这样可以单独定义他 们的操作。
案例:通过函数嵌套的方式接受三个参数,当这三种类型参数都为假时,返回fales。
def f1(i:Int):String=>(Char=>Boolean)={def f2(s:String):Char=>Boolean={def f3(c:Char):Boolean={if (i==0&&s==""&&c=='0') false else true}f3}f2}
println(f1(0)("")('0')) //结果为false
//可以用匿名函数进行简化书写,但是这种书写也会被函数的柯里化给代替
def func1(i:Int):String=>(Char=>Boolean)={s=>c=> if (i==0&&s==""&&c=='0') false else true
}
四.柯里化和闭包
闭包:如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和他所处的环境成为闭包
函数柯里化:把一个参数列表的多个参数,变成多个参数列表,每个参数都是一个小括号
函数性编程语言(scala)定是支持闭包的。它可以延长他所使用的参数的做作用域(如上面那个案例,内层函数用到了外层函数的一个局部变量或者是一个参数,为了我们在调用的时候还能分层调用,在调用的时候第二步还能使用外层函数的参数,那么闭包会把外层函数的参数或者局部变量和内层函数打包起来,保存到一个函数对象里面,存放在堆内存里面)。
柯里化:
def addCurrying(a:Int)(b:Int):Int={a+b} //一旦使用了柯里化,底层一定使用了闭包println(addCurrying(23)(32))}
五.递归
递归:一个函数/方法在函数/方法体内又调用了本身
方法调用自身
方法必须要有跳出的逻辑
方法调用自身时,传递的参数应该有规律
Scala中递归必须声明返回值类型
//递归计算阶乘
def fact(n:Int):Int={if (n==0) return 1 //这个return不能省,因为scala只能自动返回最后一行,这里不是最后一行fact(n-1)*n
}
//尾递归:递归最后一行返回的只有对于自身的调用,没有其他额外的计算,这样当前这层函数不用保存任何东西,这样就用压栈了,节省空间。
def tailFact(n:Int):Int={@tailrec //如果写的不是尾递归,idea会报错def loop(n:Int,currRes:Int):Int={if(n==0)return currResloop(n-1,currRes*n) //每次调用我不需要保存上一层的任何信息,不用压栈,做一个栈帧的覆盖就节省空间了。}loop(n,1)
}
//尾递归只有函数式编程语言才支持,比如Java就不支持
六.抽象控制
1.值调用:把计算后的值传递过去
2.名调用:把代码传递过去
//传值参数
def f0(a:Int):Unit={println("a"+a)
}def f1():Int={println("f1调用")12
}
f0(f1)
//传名参数,传递的不再是具体的值,而是代码块
def f2(a:=>Int):Unit={ //注意这里参数的类型println("a:"+a)println("a:"+a)
}
f2(f1()) //每一次用到a的时候,都会把f2中完整的代码块执行一遍。
传名调用的案例:自己实现一个while循环函数
//1.用闭包实现一个函数,将代码块作为参数传入,递归调用
def myWhile(condition:=>Boolean):(=>Unit)=>Unit={//内层函数需要递归调用,参数就是循环体(代码块)def doLoop(op:=>Unit):Unit={ if(condition){opmyWhile(condition)(op) //尾递归} }doLoop _
}n=10
myWhile(n>=1){println(n)n-=1
}//参数是一个代码块时,小括号可以省略//2.用匿名函数实现
def myWhile2(condition:=>Boolean):(=>Unit)=>Unit={//内层函数需要递归调用,参数就是循环体(代码块)op=>{ if(condition){opmyWhile2(condition)(op) //尾递归} }
}
//3.用函数柯里化实现
def myWhile(condition:=>Boolean)(op:=>Unit):Unit={if(condition){opmyWhile3(condition)(op)}
}
七.惰性加载
说明:函数的返回值被声明lazy时,函数的执行将被推迟,直到我们首次对此取值,该函数才会被执行,这种函数我们称之为惰性函数。
(不用到,不执行加载)
lazy val result:Int = sum(13,47)
println("1.函数调用")
println("2.result="+result)def sum(a:Int,b:Int):Int={printlb("3.sum调用")
}//最后输出顺序时1 3 2
相关文章:
scala高级函数快速掌握
scala高级函数一.函数至简原则二.匿名的简化原则三.高阶函数四.柯里化和闭包五.递归六.抽象控制七.惰性加载🔥函数对于scala(函数式编程语言)来说非常重要,大家一定要学明白,加油!!!…...

手写模拟SpringMvc源码
MVC框架MVC是一种设计模式(设计模式就是日常开发中编写代码的一种好的方法和经验的总结)。模型(model)-视图(view)-控制器(controller),三层架构的设计模式。用于实现前端…...

五分钟了解JumpServer V2.* 与 v3 的区别
一、升级注意项 1、梳理数据。JumpServer V3 去除了系统用户功能,将资产与资产直接绑定。当一个资产名下有多个同名账号,例如两个root用户时,升级后会自动合并最后一个root,不会同步其他root用户。升级前需保证每一个资产只拥有一…...

用友开发者中心应用构建实践指引!
基于 iuap 技术底座,用友开发者中心致力于为企业和开发者提供一站式技术服务,让人人都能轻松构建企业级应用。 本文以人力资源领域常用的应聘人员信息登记与分析功能为例,详细介绍如何在用友开发者中心使用 YonBuilder 进行应用构建。 功能…...

snap使用interface:content的基础例子
snap做包还在学习阶段,官网文档可查看:The content interface | Snapcraft documentation该例子由publiser和consumer两部分组成,一个提供一个只读的数据区,一个来进行读取其中的信息,这样就完成了content的交互。publ…...
蓝桥杯刷题第七天
第一题:三角回文数问题描述对于正整数 n, 如果存在正整数 k 使得2n123⋯k2k(k1), 则 n 称为三角数。例如, 66066 是一个三角数, 因为 66066123⋯363。如果一个整数从左到右读出所有数位上的数字, 与从右到左读出所有数位 上的数字是一样的, 则称这个数为回文数。例如…...

FinOps首次超越安全成为企业头等大事|云计算趋势报告
随着云计算在过去十年中的广泛应用,云计算用户所面临的一个持续不变的趋势是:安全一直是用户面临的首要挑战。然而,这种情况正在发生转变。 知名IT软件企业 Flexera 对云计算决策者进行年度调研已经持续12年,而今年安全问题首次…...

【深度强化学习】(3) Policy Gradients 模型解析,附Pytorch完整代码
大家好,今天和各位分享一下基于策略的深度强化学习方法,策略梯度法是对策略进行建模,然后通过梯度上升更新策略网络的参数。我们使用了 OpenAI 的 gym 库,基于策略梯度法完成了一个小游戏。完整代码可以从我的 GitHub 中获得&…...

Windows基于Nginx搭建RTMP流媒体服务器(附带所有组件下载地址及验证方法)
RTMP服务时常用于直播时提供拉流推流传输数据的一种服务。前段时间由于朋友想搭建一套直播时提供稳定数据传输的服务器,所以就研究了一下如何搭建及使用。 1、下载nginx 首先我们要知道一般nginx不能直接配置rtmp服务,在Windows系统上需要特殊nginx版本…...

交流电机驱动器中的隔离电压感应
汽车和工业终端设备,如电机驱动器、串式逆变器和机载充电器,在高电压下运行,不能安全地与人直接互动。隔离电压测量通过保护人类免受高压电路执行一个功能的影响,有助于优化操作和确保使用的安全性。 设计用于高性能,隔…...
爬取知乎问题答案
参考博客:基于Python知乎回答爬虫 jieba关键字统计可视化_知乎爬虫搜索关键词_菠萝柚王子的博客-CSDN博客 1、安装依赖包 import numpy import requests import certifi from PIL import Image from lxml import etree import jieba from wordcloud import WordClo…...
通用智能理论
将智能定义为解决矛盾的能力,用解决矛盾的概率提升来评估智能程度,以此为基础推导智能原理,建立一种新的通用智能理论。 1 前言 通用人工智能(Artificial General Intelligence)是人类长久以来的梦想。经历了一次次挫败…...

保姆级使用PyTorch训练与评估自己的MixMIM网络教程
文章目录前言0. 环境搭建&快速开始1. 数据集制作1.1 标签文件制作1.2 数据集划分1.3 数据集信息文件制作2. 修改参数文件3. 训练4. 评估5. 其他教程前言 项目地址:https://github.com/Fafa-DL/Awesome-Backbones 操作教程:https://www.bilibili.co…...

《百万在线 大型游戏服务端开发》前两章概念笔记
第1章 从角色走路说起 游戏网络通信的流程则是服务端先开启监听,等待客户端的连接,然后交互操作,最后断开。 套接字 每个Socket都包含网络连接中一端的信息。每个客户端需要一个Socket结构,服务端则需要N1个Socket结构ÿ…...

3BHE029110R0111 ABB
3BHE029110R0111 ABB变频器控制方式低压通用变频输出电压为380~650V,输出功率为0.75~400kW,工作频率为0~400Hz,它的主电路都采用交—直—交电路。其控制方式经历了以下四代。1U/fC的正弦脉宽调制࿰…...
实现防重复操作(JS与CSS)
实现防重复操作(JS与CSS) 一、前言 日常开发中我们经常会对按钮进行一个防重复点击的校验,这个通常使用节流函数来实现。在规定时间内只允许提交一次,可以有效的避免事件过于频繁的执行和重复提交操作,以及为服务器考…...

怎么合并或注销重复LinkedIn领英帐号?
您可能会发现您拥有多个领英帐户。如果您收到消息,提示您尝试使用的邮箱与另一个帐户已绑定,就表明您可能存在重复的领英帐户。如果您使用许多不同的邮箱地址,也可能会收到这样的提示。 领英精灵温馨提示: 目前,仅支持在 PC 端合并…...

Redis高频面试题汇总(中)
目录 1.什么是redis事务? 2.如何使用 Redis 事务? 3.Redis 事务为什么不支持原子性 4.Redis 事务支持持久性吗 5.Redis事务基于lua脚本的实现 6.Redis集群的主从复制模型是怎样的? 7.Redis集群中,主从复制的数据同步的步骤 …...

【Flutter从入门到入坑之三】Flutter 是如何工作的
【Flutter从入门到入坑之一】Flutter 介绍及安装使用 【Flutter从入门到入坑之二】Dart语言基础概述 【Flutter从入门到入坑之三】Flutter 是如何工作的 本文章主要以界面渲染过程为例,介绍一下 Flutter 是如何工作的。 页面中的各界面元素(Widget&…...

Web Components学习(2)-语法
一、Web Components 对 Vue 的影响 尤雨溪在创建 Vue 的时候大量参考了 Web Components 的语法,下面写个简单示例。 首先写个 Vue 组件 my-span.vue: <!-- my-span.vue --> <template><span>my-span</span> </template>…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...

linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...