【Scala】——函数式编程

1 面向对象编程和函数式编程

1.1 面向对象编程

  1. 解决问题,分解对象,行为,属性,然后通过对象的关系以及行为的调用来解决问题。
    • 对象:用户
    • 行为:登录、连接 JDBC、读取数据库
    • 属性:用户名、密码
  2. Scala 语言是一个完全面向对象编程语言。万物皆对象
  3. 对象的本质:对数据和行为的一个封装

1.2 函数式编程

  1. 解决问题时,将问题分解成一个一个的步骤,将每个步骤进行封装(函数),通过调用 这些封装好的步骤,解决问题。 例如:请求->用户名、密码->连接 JDBC->读取数据库
  2. Scala 语言是一个完全函数式编程语言。万物皆函数。
  3. 函数的本质:函数可以当做一个值进行传递

2 函数基础

2.1 基本语法

在这里插入图片描述

2.2 函数和方法的区别

  1. 为完成某一功能的程序语句的集合,称为函数。
  2. 类中的函数称之方法。
  3. Scala 语言可以在任何的语法结构中声明任何的语法
  4. 函数没有重载和重写的概念;方法可以进行重载和重写
  5. Scala 中函数可以嵌套定义
package com.scala
package chapter05object TestFunction {//(2)方法可以进行重载和重写,程序可以执行def test(): Unit = {}def test(name: String): Unit = {}def main(args: Array[String]): Unit = {// (1)Scala 语言可以在任何的语法结构中声明任何的语法import java.util.Datenew Date()def test(): Unit = {println("无参,无返回值")}test()//(3)函数没有重载和重写的概念,程序报错// def test(name: String): Unit = {////}//(4)Scala 中函数可以嵌套定义def test2(): Unit = {def test3(name: String): Unit = {println(name + "函数可以嵌套定义")}test3("zhangsan")}test2()}}

2.3 函数定义

  1. 函数 1:无参,无返回值
  2. 函数 2:无参,有返回值
  3. 函数 3:有参,无返回值
  4. 函数 4:有参,有返回值
  5. 函数 5:多参,无返回值
  6. 函数 6:多参,有返回值
package com.scala
package chapter05object TestFunctionDeclare {def main(args: Array[String]): Unit = {// 函数 1:无参,无返回值def test1(): Unit = {println("无参,无返回值")}test1()// 函数 2:无参,有返回值def test2(): String = {return "无参,有返回值"}println(test2())// 函数 3:有参,无返回值def test3(s: String): Unit = {println(s)}test3("jinlian")// 函数 4:有参,有返回值def test4(s: String): String = {return s + "有参,有返回值"}println(test4("hello "))// 函数 5:多参,无返回值def test5(name: String, age: Int): Unit = {println(s"$name, $age")}test5("dalang", 40)// 函数 6:多参,有返回值def test6(name: String, age: Int): String = {println(s"$name, $age")return name+age}test6("aaaa", 40)}}

2.4 函数参数

  1. 可变参数
def test(s:String*):Unit={println(s)
}
// 有输入参数:输出 Array
test("qwe","asd")
// 无输入参数:输出 List()
test()
  1. 如果参数列表中存在多个参数,那么可变参数一般放置在最后
def test2(name: String, s: String*): Unit = {println(name + "," + s)
}
test2("jinlian", "dalang")
  1. 参数默认值,一般将有默认值的参数放置在参数列表的后面,如果参数传递了值,那么会覆盖默认值,如果参数有默认值,在调用的时候,可以省略这个参数
def test3( name : String, age : Int = 30 ): Unit = {println(s"$name, $age")
}
// 如果参数传递了值,那么会覆盖默认值
test3("jinlian", 20)
// 如果参数有默认值,在调用的时候,可以省略这个参数
test3("dalang")
// 一般情况下,将有默认值的参数放置在参数列表的后面
def test4(sex: String = "男", name: String): Unit = {println(s"$name, $sex")
}
  1. 带名参数, Scala 函数中参数传递是,从左到右,如果参数的左边有可变参数或者有默认值的参数,可将参数指定给某个参数
def test4(sex: String = "男", name: String): Unit = {println(s"$name, $sex")
}   
test4(name = "ximenqing")

2.5 函数至简原则

  1. return 可以省略,Scala 会使用函数体的最后一行代码作为返回值
def f1(s: String): String = {s + " jinlian"
}
  1. 如果函数体只有一行代码,可以省略花括号
def f2(s:String):String = s + " jinlian"
  1. 返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起省略)
def f3( s : String ) = s + " jinlian"
  1. 如果有 return,则不能省略返回值类型,必须指定
def f4() :String = {return "ximenqing4"
}
  1. 如果函数明确声明 unit,那么即使函数体中使用 return 关键字也不起作用
def f5(): Unit = {return "dalang5"
}
  1. Scala 如果期望是无返回值类型,可以省略等号
def f6() {"dalang6"
}
  1. 如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加
def f7() = "dalang7"
println(f7())
println(f7)
  1. 如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略
def f8 = "dalang"
//println(f8())
println(f8)
  1. 如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略
def f9 = (x:String)=>{println("wusong")}
def f10(f:String=>Unit) = {f("")
}
f10(f9)
println(f10((x:String)=>{println("wusong")}))

3 函数高级

3.1 高阶函数

对于一个函数我们可以:定义函数、调用函数,但是其实函数还有更高阶的用法

3.1.1 函数作为值进行传递

  1. 调用 foo 函数,把返回值给变量 f
object TestFunctionHigh {def main(args: Array[String]): Unit = {//调用 foo 函数,把返回值给变量 f//val f = foo()val f = fooprintln(f)}def foo(): Int = {println("foo...")1}
}
  1. 在被调用函数 foo 后面加上 _,相当于把函数 foo 当成一个整体, 传递给变量 f1
object TestFunctionHigh {def main(args: Array[String]): Unit = {//在被调用函数 foo 后面加上 _,相当于把函数 foo 当成一个整体, 传递给变量 f1val f1 = foo _f1()println("-----------------------")}def foo(): Int = {println("foo...")1}
}
  1. 如果明确变量类型,那么不使用下划线也可以将函数作为整体传递给 变量
object TestFunctionHigh {def main(args: Array[String]): Unit = {//如果明确变量类型,那么不使用下划线也可以将函数作为整体传递给 变量var f2: () => Int = foof2()println("-----------------------")}def foo(): Int = {println("foo...")1}
}

3.1.2 函数作为参数进行传递

def main(args: Array[String]): Unit = {// (1)定义一个函数,函数参数还是一个函数签名;f 表示函数名称;(Int,Int) 表示输入两个 Int 参数;Int 表示函数返回值def f1(f: (Int, Int) => Int): Int = {f(2, 4)}// (2)定义一个函数,参数和返回值类型和 f1 的输入参数一致def add(a: Int, b: Int): Int = a + b// (3)将 add 函数作为参数传递给 f1 函数,如果能够推断出来不是调用,_ 可以省略println(f1(add))println(f1(add _))//可以传递匿名函数
}

3.1.3 函数作为函数返回值返回

def main(args: Array[String]): Unit = {def f1() = {def f2() = {println("f2----")}f2 _}val f = f1()// 因为 f1 函数的返回值依然为函数,所以可以变量 f 可以作为函数继续调用f()// 上面的代码可以简化为f1()()
}

3.2 匿名函数

3.2.1 概述

没有名字的函数就是匿名函数
(x:Int)=>{函数体}
x:表示输入参数类型;Int:表示输入参数类型;函数体:表示具体代码逻辑

3.2.2 传递匿名函数至简原则:

  1. 参数的类型可以省略,会根据形参进行自动的推导
  2. 类型省略之后,发现只有一个参数,则圆括号可以省略;其他情况:没有参数和参数超过 1 的永远不能省略圆括号。
  3. 匿名函数如果只有一行,则大括号也可以省略
  4. 如果参数只出现一次,则参数省略且后面参数可以用_代替

3.2.2 案例实操

  1. 传递的函数有一个参数
def main(args: Array[String]): Unit = {// (1)定义一个函数:参数包含数据和逻辑函数def operation(arr: Array[Int], op: Int => Int) = {for (elem <- arr) yield op(elem)}// (2)定义逻辑函数def op(ele: Int): Int = {ele + 1}// (3)标准函数调用val arr = operation(Array(1, 2, 3, 4), op)println(arr.mkString(","))// (4)采用匿名函数val arr1 = operation(Array(1, 2, 3, 4), (ele: Int) => {ele + 1})println(arr1.mkString(","))// (4.1)参数的类型可以省略,会根据形参进行自动的推导;val arr2 = operation(Array(1, 2, 3, 4), (ele) => {ele + 1})println(arr2.mkString(","))// (4.2)类型省略之后,发现只有一个参数,则圆括号可以省略;其他情 况 :没有参数和参数超过1的永远不能省略圆括号 。val arr3 = operation(Array(1, 2, 3, 4), ele => {ele + 1})println(arr3.mkString(","))// (4.3) 匿名函数如果只有一行,则大括号也可以省略val arr4 = operation(Array(1, 2, 3, 4), ele => ele + 1)println(arr4.mkString(","))//(4.4)如果参数只出现一次,则参数省略且后面参数可以用_代替val arr5 = operation(Array(1, 2, 3, 4), _ + 1)println(arr5.mkString(","))
}
  1. 传递的函数有两个参数
def main(args: Array[String]): Unit = {def calculator(a: Int, b: Int, op: (Int, Int) => Int): Int = {op(a, b)}// (1)标准版println(calculator(2, 3, (x: Int, y: Int) => {x + y}))// (2)如果只有一行,则大括号也可以省略println(calculator(2, 3, (x: Int, y: Int) => x + y))// (3)参数的类型可以省略,会根据形参进行自动的推导;println(calculator(2, 3, (x, y) => x + y))// (4)如果参数只出现一次,则参数省略且后面参数可以用_代替println(calculator(2, 3, _ + _))}

3.3 函数柯里化&闭包

3.3.1 说明

  1. 闭包:如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和他所处的 环境,称为闭包
  2. 函数柯里化:把一个参数列表的多个参数,变成多个参数列表。函数柯里化,其实就是将复杂的参数逻辑变得简单化,函数柯里化一定存 在闭包

3.3.2 案例

  1. 闭包
 def main(args: Array[String]): Unit = {def f1() = {var a: Int = 10def f2(b: Int) = {a + b}f2 _}// 在调用时,f1 函数执行完毕后,局部变量 a 应该随着栈空间释放掉val f = f1()// 但是在此处,变量 a 其实并没有释放,而是包含在了 f2 函数的内部,形 成了闭合的效果println(f(3))println(f1()(3))}
  1. 函数柯里化
def main(args: Array[String]): Unit = {// 函数柯里化,其实就是将复杂的参数逻辑变得简单化,函数柯里化一定存 在闭包def f3()(b: Int) = {var a: Int = 10println("b="+b)a + b}println(f3()(3))
}

3.4 递归

一个函数/方法在函数/方法体内又调用了本身,我们称之为递归调用

  1. 方法调用自身
  2. 方法必须要有跳出的逻辑
  3. 方法调用自身时,传递的参数应该有规律
  4. scala 中的递归必须声明函数返回值类型
def main(args: Array[String]): Unit = {// 阶乘// 递归算法println(test(5))
}def test(i: Int): Int = {if (i == 1) {1} else {i * test(i - 1)}
}

3.5 控制抽象

3.5.1 值调用

把计算后的值传递过去

def main(args: Array[String]): Unit = {def f = () => {println("f...")10}foo(f())
}def foo(a: Int): Unit = {println(a)println(a)
}

3.5.2 名调用

把代码传递过去

def main(args: Array[String]): Unit = {def f = () => {println("f...")10}foo(f())
}def foo(a: => Int): Unit = { //注意这里变量 a 没有小括号了println(a)println(a)
}

3.5.3 案例

def main(args: Array[String]): Unit = {// (1)传递代码块foo({println("aaa")10})// (2)小括号可以省略foo {println("aaa")10}}def foo(a: => Int): Unit = {println(a)println(a)
}
def main(args: Array[String]): Unit = {var i:Int = 1myWhile(i <= 10){println(i)i +=1}
}
def myWhile(condition: =>Boolean)(op: =>Unit):Unit={if (condition){opmyWhile(condition)(op)}
}

3.6 惰性加载

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

def main(args: Array[String]): Unit = {lazy val res = sum(10, 30)println("----------------")println("res=" + res)println("----------------------------------------------------------------")val res1 = sum(10, 30)println("----------------")println("res1=" + res1)
}def sum(n1: Int, n2: Int): Int = {println("sum 被执行。。。")n1 + n2
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/608088.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Three.js 纹理贴图的实现

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 纹理贴图简介 当我们创建一个网格时&#xff0c;比如我们不起眼的立…

IP定位应对恶意IP攻击:保护网络安全的新策略

随着网络攻击的日益猖獗&#xff0c;恶意IP攻击成为网络安全领域的一大挑战。传统的安全防护手段在应对此类攻击时显得力不从心。近年来&#xff0c;通过IP定位这一新技术&#xff0c;为应对恶意IP攻击提供了新的解决思路。 IP定位技术通过分析网络流量中的IP地址&#xff0c;能…

如何创建VPC并配置安全组以保护您的阿里云服务器

将您的基础架构放在云上意味着您可以接触到全球的许多人。但是&#xff0c;这也意味着不怀好意的人可以访问您的服务。保护您的云网络非常重要。阿里云提供虚拟专用网络 &#xff08;VPC&#xff09;&#xff0c;这是一个安全隔离的私有云&#xff0c;将您的弹性计算服务 &…

用Python来制作一个微信聊天机器人

1. 效果展示 通过本地搭建一个flask服务器来接收信息&#xff0c;这里我简单使用展示&#xff0c;就没有对接收的信息进行处理了。 信息接收展示 发送信息展示 这里就直接使用python发送一个post请求即可&#xff0c;可以发送文字或者图片 代码展示 接收信息 #!/usr/bin/e…

[足式机器人]Part3 机构运动学与动力学分析与建模 Ch00-2(4) 质量刚体的在坐标系下运动

本文仅供学习使用&#xff0c;总结很多本现有讲述运动学或动力学书籍后的总结&#xff0c;从矢量的角度进行分析&#xff0c;方法比较传统&#xff0c;但更易理解&#xff0c;并且现有的看似抽象方法&#xff0c;两者本质上并无不同。 2024年底本人学位论文发表后方可摘抄 若有…

C++的一些书籍整理(个人学习)

UNIX环境高级编程&#xff08;第三版&#xff09; UNXI网络编程卷1 网络编程的笔记 收藏 我会了 一堆书 这个仓 数据库连接池原理介绍常用连接池介绍

《More Effective C++》学习

条款1&#xff1a;仔细区别 pointers 和 references 引用应该被初始化&#xff0c;指针可以不被初始化。不存在指向空值的引用这个事实意味着使用引用的代码效率比使用指针的要高。因为在使用引用之前不需要测试它的合法性。指针与引用的另一个重要的不同是指针可以被重新赋值…

mac环境桌面版docker错误修改daemon.json配置后,启动失败,一直卡在Docker Engine starting界面的解决方法

如下图&#xff1a;当桌面版docker的配置被错误的修改后&#xff0c;配置修改重启应用时&#xff0c;会一直卡在启动界面 此时需要找到mac下该桌面版docker的配置文件位置&#xff0c;手动修改恢复&#xff0c;然后重启应用。 daemon.json文件一般默认在隐藏文件夹下&#xff0…

SSL证书安装在哪?

安装SSL证书的具体步骤取决于你使用的服务器软件和操作系统。一般来说&#xff0c;SSL证书通常用于加密网站上的数据传输&#xff0c;因此安装过程主要涉及到Web服务器的配置。以下是一般步骤&#xff0c;但请注意这可能因你的具体环境而异。 永久免费SSL证书_永久免费https证…

一天一个设计模式---单例模式

概念 单例模式是一种创建型设计模式&#xff0c;其主要目的是确保一个类只有一个实例&#xff0c;并提供一个全局访问点。这意味着在应用程序中的任何地方&#xff0c;只能有一个实例存在&#xff0c;而不会创建多个相同类型的实例。 具体内容 单例模式通常包括以下几个要素…

Pytorch种torch.cat与torch.stack的区别

torch.cat 和 torch.stack 是 PyTorch 中用于拼接张量的两个不同的函数&#xff0c;它们的主要区别在于拼接的方式和创建的维度。 torch.cat&#xff1a; 拼接方式&#xff1a; torch.cat 是按照给定的维度&#xff08;dim 参数&#xff09;将多个张量沿着该维度拼接。在拼接的…

Unity 利用UGUI之Slider制作进度条

在Unity中使用Slider和Text组件可以制作简单的进度条。 首先在场景中右键->UI->Slider&#xff0c;新建一个Slider组件&#xff1a; 同样方法新建一个Text组件&#xff0c;最终如图&#xff1a; 创建一个进度模拟脚本&#xff0c;Slider_Progressbar.cs using System.C…

矿泉水除硝酸盐的方法分析

摘要&#xff1a;饮用水中的硝酸盐污染已成为全球性问题&#xff0c;对人类健康构成威胁。本文将介绍离子交换树脂技术在饮用水除硝酸盐方面的应用与优势&#xff0c;帮助您了解如何有效去除饮用水中的硝酸盐&#xff0c;保障水质安全。 正文&#xff1a; 一、饮用水中硝酸盐…

使用kubesphere的devops部署SpringCloud项目

devops部署SpringCloud项目 环境说明部署流程创建DevOps工程填写流水线信息创建流水线jenkinsfileDockerfiledeploy.yaml 环境说明 已经安装kubesphere的devops组件安装教程可参考官方文档:https://v3-1.docs.kubesphere.io/zh/docs/pluggable-components/devops/ 部署流程 创…

redis 从0到1完整学习 (十六):内存回收之 key 过期处理策略

文章目录 1. 引言2. redis 源码下载3. redisDb 结构体4. Redis 过期 key 的处理策略4.1 惰性删除 (Lazy Expiration)4.2 定期删除 (Active Expire / Periodic Expiration)* 5. 参考 1. 引言 前情提要&#xff1a; 《redis 从0到1完整学习 &#xff08;一&#xff09;&#xff…

Lumerical Monitors------frequency domain power monitor 频率域功率监视器

frequency domain power monitor 频率域功率监视器 引言正文引言 这里给大家介绍一下 frequency domain power monitor。 正文 首先,我们可以通过以下方式添加 frequency domain power monitor 到我们的工程文件中: 在 general tab 中,有一个共同的监视器设置 simulati…

苍穹外卖Day01——总结1

总结1 1. 软件开发整体介绍1.1 软件开发流程1.2 角色分工1.3 软件环境 2. 苍穹外卖项目介绍2.1 项目介绍2.2 技术选项 3. Swagger4. 补充内容&#xff08;待解决...&#xff09; 1. 软件开发整体介绍 1.1 软件开发流程 1.2 角色分工 从角色分工里面就可以查看自己以后从事哪一…

跨国制造业组网方案解析,如何实现总部-分支稳定互联?

既要控制成本&#xff0c;又要稳定高效&#xff0c;可能吗&#xff1f; 在制造企业积极向“智造”发展、数字化转型的当下&#xff0c;物联网、人工智能、机器人等新型设备加入到生产、管理环节&#xff0c;为企业内部数据传输提出了更高的要求。而当企业规模扩大&#xff0c;数…

记录一次接近24万条数据导入Mysql的过程

由于开发项目的需求&#xff0c;之前有部分数据要写入阿里云的表格存储&#xff0c;过了一年多时间&#xff0c;表A的数据量接近24万条&#xff0c;现在需要将表A的数据转到Mysql中。 利用官方工具导出数据后&#xff0c;发现文件里面有238999条数据&#xff0c;文件大小是460…

Unity中URP下深度图的线性转化

文章目录 前言一、_ZBufferParams参数有两组值二、LinearEyeDepth1、使用2、Unity源码推导&#xff1a;3、使用矩阵推导&#xff1a; 三、Linear01Depth1、使用2、Unity源码推导3、数学推导&#xff1a; 前言 在之前的文章中&#xff0c;我们实现了对深度图的使用。因为&#…