当前位置: 首页 > news >正文

Scala核心编程(五)函数式编程基础

一、函数式编程概述1.1 函数式编程内容体系Scala 的函数式编程内容分为基础和高级两大部分阶段内容函数式编程基础函数定义/声明、函数运行机制、递归、过程、惰性函数和异常函数式编程高级值函数(函数字面量)、高阶函数、闭包、应用函数、柯里化函数、抽象控制…1.2 文章顺序说明在 Scala 中函数式编程和**面向对象编程(OOP)**是融合在一起的学习函数式编程需要 OOP 的知识学习 OOP 需要函数式编程的基础推荐学习顺序函数式编程基础 → 面向对象编程 → 函数式编程高级1.3 核心概念辨析概念说明方法在 Scala 中方法和函数几乎可以等同定义、使用、运行机制都一样只是函数的使用方式更加灵活多样函数完成某一功能的程序指令(语句)的集合函数式编程一种编程范式把函数当做一等公民充分利用函数支持函数的多种使用方式面向对象编程以对象为基础的编程方式关键区别在 Scala 中函数是一等公民像变量一样既可以作为函数的参数使用也可以将函数赋值给一个变量函数的创建不用依赖于类或者对象。而在 Java 中函数的创建则要依赖于类、抽象类或者接口。1.4 函数式编程的特点函数式编程是一种编程范式programming paradigm它属于结构化编程的一种主要思想是把运算过程尽量写成一系列嵌套的函数调用函数式编程中将函数也当做数据类型因此可以接受函数当作输入参数和输出返回值函数式编程中最重要的就是函数二、为什么需要函数2.1 传统方式的问题以输入两个数和一个运算符得到结果为例传统方式存在代码冗余— 相同逻辑的代码重复编写不利于代码维护— 修改时需要改动多处2.2 函数的解决方案将重复的功能抽取出来形成函数实现代码复用defcalculate(n1:Int,n2:Int,oper:String):Unit{if(oper){println(res(n1n2))}elseif(oper-){println(res(n1-n2))}}三、函数的定义3.1 基本语法def函数名([参数名:参数类型],...)[:返回值类型]{语句...return返回值}3.2 语法说明要点说明def函数声明关键字definition[参数名: 参数类型]表示函数的输入参数列表可以没有。如果有多个参数使用逗号间隔函数体语句表示为了实现某一功能代码块返回值函数可以有返回值也可以没有3.3 返回值形式形式语法说明形式1: 返回值类型 明确指定返回值类型形式2返回值类型不确定使用类型推导完成形式3无等号表示没有返回值return不生效重要规则如果没有return默认以执行到最后一行的结果作为返回值。四、函数调用机制4.1 通俗理解函数调用类似于下达命令程序员调用方法 → 给方法必要的输入方法执行后 →返回结果给程序员4.2 函数调用过程栈机制objectTest01{defmain(args:Array[String]):Unit{valn11valn23valressum(n1,n2)// 调用 sum 函数println(resres)}defsum(n1:Int,n2:Int):Int{returnn1n2}}函数执行原则在编译器底层当执行一个函数/方法时就会开辟一个新的方法栈每个栈的空间是相互独立的数据也是独立的五、递归调用5.1 基本介绍一个函数在函数体内又调用了本身我们称为递归调用。5.2 快速入门示例// 示例1递归调用在打印语句之前deftest(n:Int){if(n2){test(n-1)}println(nn)}// 示例2递归调用在打印语句之后deftest2(n:Int){if(n2){test2(n-1)}else{println(nn)}}思考调用test(4)和test2(4)分别输出什么5.3 递归需要遵守的重要原则程序执行一个函数时就创建一个新的受保护的独立空间新函数栈函数的局部变量是独立的不会相互影响递归必须向退出递归的条件逼近否则就是无限递归死龟当一个函数执行完毕或者遇到return就会返回遵守谁调用就将结果返回给谁5.4 递归课堂练习题题1斐波那契数使用递归求斐波那契数1, 1, 2, 3, 5, 8, 13…给定整数 n求出它的斐波那契数。deffibonacci(n:Int):Int{if(n1||n2)1elsefibonacci(n-1)fibonacci(n-2)}题2求函数值已知f(1) 3; f(n) 2 * f(n-1) 1使用递归求 f(n)。deff(n:Int):Int{if(n1)3else2*f(n-1)1}题3猴子吃桃子问题有一堆桃子猴子第一天吃了其中的一半并再多吃了一个以后每天都吃其中的一半然后再多吃一个。当到第十天时想再吃时还没吃发现只有1个桃子了。问题最初共多少个桃子defpeach(day:Int):Int{if(day10)1else(peach(day1)1)*2}六、函数注意事项和细节讨论6.1 形参与调用函数的形参列表可以是多个如果函数没有形参调用时可以不带()形参列表和返回值列表的数据类型可以是值类型和引用类型6.2 返回值类型推断Scala 中的函数可以根据函数体最后一行代码自行推断函数返回值类型。那么在这种情况下return关键字可以省略// 完整写法defgetSum(n1:Int,n2:Int):Int{n1n2}// 省略返回值类型类型推导defgetSum(n1:Int,n2:Int){n1n2}因为 Scala 可以自行推断所以在省略return关键字的场合返回值类型也可以省略如果函数明确使用return关键字那么函数返回就不能使用自行推断了这时要明确写成: 返回类型 。当然如果你什么都不写即使有return返回值为()如果函数明确声明无返回值声明Unit那么函数体中即使使用return关键字也不会有返回值如果明确函数无返回值或不确定返回值类型那么返回值类型可以省略或声明为Any6.3 嵌套函数Scala 语法中任何的语法结构都可以嵌套其他语法结构灵活即函数中可以再声明/定义函数类中可以再声明类方法中可以再声明/定义方法6.4 默认参数Scala 函数的形参在声明参数时直接赋初始值默认值这时调用函数时如果没有指定实参则会使用默认值。如果指定了实参则实参会覆盖默认值defsayOk(name:Stringjack):String{name ok!}sayOk()// 输出: jack ok!sayOk(tom)// 输出: tom ok!如果函数存在多个参数每一个参数都可以设定默认值。传递的参数到底是覆盖默认值还是赋值给没有默认值的参数默认按照声明顺序从左到右。在这种情况下可以采用带名参数defmysqlCon(add:Stringlocalhost,port:Int3306,user:Stringroot,pwd:Stringroot):Unit{println(addadd)println(portport)println(useruser)println(pwdpwd)}// 使用带名参数deff6(p1:Stringv1,p2:String){println(p1p2)}f6(v2)// p1 v2, p2 报错没有默认值f6(p2v2)// p1 v1, p2 v26.5 形参不可变Scala 函数的形参默认是 val 的因此不能在函数中进行修改6.6 递归函数的类型声明递归函数未执行之前是无法推断出来结果类型在使用时必须有明确的返回值类型// 错误递归不能使用类型推断deff8(n:Int){// ❌ 编译错误if(n0)1elsen*f8(n-1)}// 正确必须指定返回类型deff8(n:Int):Int{// ✅ 正确if(n0)1elsen*f8(n-1)}6.7 可变参数Scala 函数支持可变参数// 支持0到多个参数defsum(args:Int*):Int{// args 是集合通过 for 循环可以访问到各个值}// 支持1到多个参数defsum(n1:Int,args:Int*):Int{}注意可变参数需要写在形参列表的最后。七、过程Procedure7.1 基本介绍将函数的返回类型为Unit的函数称之为过程procedure。如果明确函数没有返回值那么等号可以省略。// f10 没有返回值使用 Unit 来说明// 这时这个函数我们也叫过程(procedure)deff10(name:String):Unit{println(name hello )}// 等号可以省略deff10(name:String){println(name hello )}7.2 注意事项注意区分如果函数声明时没有返回值类型但是有号可以进行类型推断最后一行代码。这时这个函数实际是有返回值的该函数并不是过程。开发工具的自动代码补全功能虽然会自动加上 Unit但是考虑到 Scala 语言的简单、灵活最好不加。八、惰性函数Lazy Evaluation8.1 应用场景惰性计算尽可能延迟表达式求值是许多函数式编程语言的特性。惰性集合在需要时提供其元素无需预先计算它们这带来了一些好处您可以将耗时的计算推迟到绝对需要的时候您可以创造无限个集合只要它们继续收到请求就会继续提供元素Java 并没有为惰性提供原生支持Scala 提供了。8.2 Java 实现懒加载的代码publicclassLazyDemo{privateStringproperty;// 属性也可能是一个数据库连接文件等资源publicStringgetProperty(){if(propertynull){// 如果没有初始化过那么进行初始化propertyinitProperty();}returnproperty;}privateStringinitProperty(){returnproperty;}}比如常用的单例模式懒汉式实现时就使用了上面类似的思路。8.3 Scala 惰性函数当函数返回值被声明为 lazy 时函数的执行将被推迟直到我们首次对此取值该函数才会执行。这种函数我们称之为惰性函数在 Java 的某些框架代码中称之为懒加载延迟加载。defmain(args:Array[String]):Unit{lazyvalressum(10,20)// 此时 sum 不会执行println(---------------)println(resres)// 在要使用 res 前才执行 sum}defsum(n1:Int,n2:Int):Int{println(sum() 执行了..)returnn1n2}8.4 注意事项和细节lazy不能修饰 var 类型的变量不但是在调用函数时加了lazy会导致函数的执行被推迟在声明一个变量时如果声明了lazy那么变量值的分配也会推迟lazyvali10// i 的值分配会被推迟到首次使用时九、异常处理9.1 基本介绍Scala 提供try和catch块来处理异常try块用于包含可能出错的代码catch块用于处理try块中发生的异常语法处理上和 Java 类似但是又不尽相同。9.2 Java 异常处理回顾try{// 可疑代码inti0;intb10;intcb/i;// 执行代码时会抛出 ArithmeticException 异常}catch(Exceptione){e.printStackTrace();}finally{// 最终要执行的代码System.out.println(java finally);}Java 异常处理注意点Java 语言按照try—catch-catch...—finally的方式来处理异常不管有没有异常捕获都会执行finally因此通常可以在finally代码块中释放资源可以有多个catch分别捕获对应的异常这时需要把范围小的异常类写在前面把范围大的异常类写在后面否则编译错误9.3 Scala 异常处理举例try{valr10/0}catch{caseex:ArithmeticExceptionprintln(捕获了除数为零的算数异常)caseex:Exceptionprintln(捕获了异常)}finally{// 最终要执行的代码println(scala finally...)}9.4 Scala 异常处理小结要点说明1将可疑代码封装在try块中。在try块之后使用了一个catch处理程序来捕获异常。如果发生任何异常catch处理程序将处理它程序将不会异常终止2Scala 的异常的工作机制和 Java 一样但是 Scala没有 “checked(编译期)” 异常即 Scala 没有编译异常这个概念异常都是在运行的时候捕获处理3用throw关键字抛出一个异常对象。所有异常都是Throwable的子类型。throw表达式是有类型的就是Nothing因为 Nothing 是所有类型的子类型所以throw表达式可以用在需要类型的地方4在 Scala 里借用了模式匹配的思想来做异常的匹配因此在catch的代码里是一系列case子句来匹配异常5异常捕捉的机制与其他语言中一样如果有异常发生catch子句是按次序捕捉的。因此在catch子句中越具体的异常越要靠前越普遍的异常越靠后6finally子句用于执行不管是正常处理还是有异常发生时都需要执行的步骤一般用于对象的清理工作这点和 Java 一样7Scala 提供了throws关键字来声明异常。可以使用方法定义声明异常。在 scala 中可以使用throws注释来声明异常defmain(args:Array[String]):Unit{f11()}throws(classOf[NumberFormatException])// 等同于 NumberFormatException.classdeff11(){abc.toInt}十、函数练习题10.1 打印金字塔编写一个函数从终端输入一个整数打印出对应的金字塔* *** ***** ******* *********10.2 打印乘法表编写一个函数从终端输入一个整数(1-9)打印出对应的乘法表1×11 1×22 2×24 1×33 2×36 3×39 ...10.3 二维数组转置编写函数对给定的一个二维数组(3×3)转置1 2 3 1 4 7 4 5 6 → 2 5 8 7 8 9 3 6 9总结本文系统介绍了 Scala 函数式编程的基础知识包括函数的定义与调用机制递归调用的原理与练习函数的多种细节默认参数、可变参数、类型推断等过程Procedure的概念惰性函数Lazy Evaluation的应用异常处理的语法与特点掌握这些基础知识后就可以进一步学习 Scala 的面向对象编程然后再深入到函数式编程的高级特性高阶函数、闭包、柯里化等。
http://www.zskr.cn/news/1396566.html

相关文章:

  • 开源界报表扛把子:JimuReport积木报表到底是个什么产品?优势在哪,又有哪些竞品
  • AI Agent Harness实时计算集成:低延迟管控
  • 王铎行书立轴《赠静观长老方外友之二首》欣赏
  • 全国陪诊顾问报名条件详解,零基础、宝妈、上班族都能报名吗? - 深鉴新闻
  • 2026年苏州机械工厂GEO优化哪家好?| 行业排名新优势 - 资讯快报
  • AI智能体时代来了!一个让普通人也能1人运营一家公司的开源社区火了
  • Taotoken助力嵌入式场景下的智能对话应用开发
  • Redis学习总结
  • 5分钟上手Translumo:打破语言障碍的Windows实时屏幕翻译神器
  • 通用电机驱动与功率控制模块从0到1高水平总体设计方案
  • 降权、预算归零、错失窗口期:2026年企业选择SEO服务商最容易踩的三个大坑 - GEO优化
  • 基于Next.js与Supabase构建AI职位聚合平台:架构设计与工程实践
  • 市面上的3D低代码编辑器真有黑科技?拆开底层:全是Three.js套壳!
  • 长期使用Taotoken服务在API稳定性与路由容灾方面的观察
  • MySQL 表约束全解:从原理、用法到实战案例(入门必看)
  • Redis 五大基础数据类型详解:底层原理、常用命令与 Spring Boot 实战
  • HarmonyOS 6 ChipGroup Symbol 图标使用文档
  • DeepSeek降AI提示词大全+热门降AI工具横向测评:我把AI率干到了6%! - 殷念写论文
  • ClaudeCode入门11-CLAUDE.md深度配置(小白入门:让AI真正“懂“你的项目,效率翻10倍的秘密武器)
  • 【深度解析】Open Human:Local-First 记忆树驱动的桌面 AI Agent 架构与实战
  • 面试官:Plan-Execute-Replan 和 ReAct 有啥区别?
  • 【会议征稿通知 | 中南民族大学主办 | IET出版 | EI 、Scopus稳定检索】第十一届人工智能与工程管理国际学术会议(ICAIEM 2026)
  • FlashAttention在昇腾NPU上的极致优化:从原理到实践
  • 京东三面:Function Calling 和 MCP 都能做工具调用,那具体什么场景下该选哪个?
  • 物联网能量预测:多算法融合框架在嵌入式平台的实现与优化
  • 2026私域SCRM工具热门排行榜
  • 2026年香港及大陆地区十大GEO(生成式引擎优化)服务商及GEO深度研究报告
  • 保姆级教程:在讯为RK3588开发板上从零构建带桌面的Ubuntu 20.04.5系统(含WiFi/蓝牙驱动配置)
  • 【算法分析与设计】第11篇:图的表示与遍历算法:BFS与DFS的扩展性质
  • 自动化部署项目软件 Jenkins