Scala之函数式编程

news2025/1/18 3:19:41

目录

函数和方法的区别:

 参数默认值:

 函数至简原则---能省则省:

至简原则细节

匿名函数的化简:

匿名函数至简原则:

高阶函数:

高阶函数的三种用法:

(1)函数可以作为值进行传递

(2)函数可以作为参数进行传递**

匿名化简:

柯里化写法:

闭包:

递归:

优化递归:尾递归优化

控制抽象:

值调用:

名调用:

懒加载:

函数和方法的区别:


方法和函数的区别就是在位置上的不同

方法--是在类中表示(面向对象)-----伴生对象中的方法(相当于静态方法)  或者在伴生类中定义方法

写在其他位置的都是函数

函数是支持嵌套的但是并不支持函数的重载和重写(重载和重写是针对的类中的方法而言)

Scala中也有可变参数,不过与Java不同  

def main(args: Array[String]): Unit = {
    def sayhi(name: String*): Unit={
      println(s"hi $name")
    }
    sayhi()
    sayhi("shdus")
    sayhi("sdsdsd","shdushd")
  }

执行结果

 参数默认值:

(Java中不存在默认值   可通过重载实现)

  def main(args: Array[String]): Unit = {
    def sayhi(name: String="zhangsan"): Unit={
      println(s"hi $name")
    }
    sayhi()
    sayhi("shdus")
    //sayhi("sdsdsd","shdushd")
  }

执行结果:

 当想使用默认参数时,且有多个参数时  需要使用带名参数

 def main(args: Array[String]): Unit = {
    def sayhi(name: String="zhangsan",age :Int): Unit={
      println(s"hi $name age is $age")
    }
    sayhi(age = 18)
    sayhi("shdus",18)
    //sayhi("sdsdsd","shdushd")
  }

执行结果:

 函数至简原则---能省则省:

至简原则细节

1 return 可以省略, Scala 会使用函数体的最后一行代码作为返回值

                 特殊情况  return 不能省略:

    //
    def sayhi2(name :String) :String ={
      if(name==null)
        {
          return ""
        }
      println(s"Hi $name")
       name
    }

比如 传入参数为null  这个return 就不能省略  这里要作为程序的一个出口

如果省略 则会执行下边的语句   返回name

2 )如果函数体只有一行代码,可以省略花括号
                 如果不是一行代码而且省略了
3 )返回值类型如果能够推断出来,那么可以省略(和返回值类型一起省略)
                        //函数式编程最终省略的结果是 只保留传入的是什么  传出的是什么

4)如果有 return,则不能省略返回值类型,必须指定

因为每一行代码都是一个代码块   如果不写返回类型 就会返回默认最后一行代码 这时return name的返回值类型为nothing类型

  def sayhi5(name :String):String={
      println(s"hi $name")
      return name
    }
                        
5 如果函数明确声明 unit,那么即使函数体中使用 return 关键字也不起作用
(6)Scala 如果期望是无返回值类型,可以省略等号
(7)如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加
(8)如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略
9 )如果不关心名称,只关心逻辑处理,那么函数名( def )可以省略----匿名函数
=>前后分别是传入参数和返回值  =之前的是传入参数与返回值类型 = 之后 是传入的变量名 与实现逻辑)
(匿名函数中没有结果类型)
    val function: (String, Int) => String = (name: String, age: Int) => name + "的年龄是" + age

匿名函数的化简:

匿名函数至简原则:

(1)参数的类型可以省略,会根据形参进行自动的推导
可根据后边推到前面    也可根据前面推到后边  一般都是化简后边的
    val function1 = (name: String, age: Int) => name + "的年龄是" + age
    //后推前
    val function2: (String, Int) => String = (name,age) => name + "的年龄是" + age
//前面推后边
(2)类型省略之后,发现只有一个参数,则圆括号可以省略;其他情况:没有参数和参
数超过 1 的永远不能省略圆括号。
(3)匿名函数如果只有一行,则大括号也可以省略
多行不可以省略

val function3: (String, Int) => String = (name: String, age: Int) =>
  {
    println(name + "的年龄是" + age+"666")
    name + "的年龄是" + age
  }
(4)如果(所有)参数(都)只出现一次,则参数省略且后面参数可以用_代替(但是只剩下_是避不可以的)(并且是在已经经历了其他的函数化简的前提下才可替代,无法在不进行其他化简的前提下替代)
    val function5 :(Int,Int)=>Int     //输入类型  输出类型
    = {
        2*_+4*_
      }

高阶函数:

高阶函数的三种用法:

(1)函数可以作为值进行传递

是将这个函数当作值进行传递   

val function: String => String = sayHi _
    function("tangxiaocong")

(2)函数可以作为参数进行传递**

先构造一个抽象函数   再调用的时候 当作参数传递真正的逻辑

高阶函数接受一个或多个函数作为参数,并/或返回一个函数作为结果。

 def operaXY(x:Int,y:Int,func:(Int,Int)=>Int):Int={
      func(x,y)
    }
    def sumXY(x:Int,y:Int): Int =x+y

    val i: Int = operaXY(10, 20, sumXY)
        println(i);    

(3)柯里化函数:

详见下文 

不化简的匿名:

    def operaXY(x:Int,y:Int,func:(Int,Int)=>Int):Int={
      func(x,y)
    }
    val i: Int = operaXY(10, 20, (x:Int,y:Int)=>x-y)
        println(i);

匿名化简:

    (1)化简类型

    (2)化简xy使用_代替

def operaXY(x:Int,y:Int,func:(Int,Int)=>Int):Int={
      func(x,y)
    }
    val i: Int = operaXY(10, 20, _-_)
        println(i);

(3)函数可以作为函数返回值返回***

涉及到函数的一个嵌套,一级调用返回的是一个函数  二级调用返回值

 def sumxy1(x:Int)={
      def sumy(y:Int): Int =
      {
        x+y
      }
      sumy _
    }

    val function1: Int => Int = sumxy1(10)
    println("歇一会")
    val i1: Int = function1(20)
    println(i1)

使用匿名函数进行化简

将等号后边的匿名函数作为返回值进行返回
 def sumxy2(x: Int): Int => Int = (y: Int) => x + y // 将等号后边的匿名函数作为返回值进行返回
    val intToInt: Int => Int = sumxy2(58)
    val i3: Int = intToInt(23)
    println(i3)

再次对匿名函数进行化简:
这种化简就是过度化简,难懂,不建议

 def sumxy3(x: Int): Int => Int = x + _ 

柯里化写法:

为了防止过度化简,作者引入了一个数学概念---柯里化的写法:
把多个形参的参数列表打散成一个形参的多个参数列表

 def KlH(c:Char)(s:String)(i:Int)={
      c !='0' || s != "" || i !=0
    }
    println(KlH('0')("")(0))

闭包:

闭包:函数式编程的标配

闭包 :如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和他所处的
环境,称为闭包(防止嵌套造成栈溢出)
闭包让代码更加灵活
(闭包其实就是把外层的变量打包成常量让内层函数使用)
 def sumx(x:Int)={
      def sumy(y:Int):Int={
        x+y
      }
      sumy _
    }

上述采用的相当于是柯里化写法--先进行第一层调用  传入x再传递给内层函数  让x从变量变成常量,防止多次嵌套造成栈溢出

    val function: Int => Int = sumx(23)
    val i: Int = function(34)
    println(i)

递归:

递归:嵌套调用自身的函数
递归其实是不如循环快的,因为递归还是会造成压栈
  def jc(n: Int):Long ={
//递归:嵌套调用自身的函数
      if(n==1)
          1
      else
        jc(n-1)*n
    }
    println(jc(5))

优化递归:尾递归优化

尾递归:最后递归调用函数的一行 只有自身的函数  没有其他值

实际尾递归是用到了闭包  递归没办法用闭包(闭包   把上一层的变量在本层变成常量,减少压栈次数----引入了res变量)(其实相当于定义一个变量当作累加器,来替代压栈)

    def jc1(n: Int,res:Long=1):Long ={
      //递归:嵌套调用自身的函数
      if(n==1)
        res
      else
        jc1(n-1,res*n)
    }

判断是否是尾递归,可以使用一个注解----@tailrec(不是尾递归会报错)

控制抽象:

函数定义有值调用和名调用(两种方式的传参方式不同)

值调用:

--将代码块的结果作为参数传入函数中,使用参数时,只带入结果

(值调用是指函数在调用时,先计算参数的值,然后再将这个值传递给函数。这意味着每个参数都只计算一次

名调用:

--直接将整个代码块传入参数中,使用一次参数就会运行一次

(名调用是指函数在调用时,将参数的表达式作为代码块传递给函数。这意味着每次函数使用参数时都会重新计算它的值。)

  //值调用
    def sayHi1(name:String):Unit={
      println("函数调用")
      println(s"$name  hi")
      println(s"$name  hi")
    }
    sayHi1({
      println("hello")
      "linhai"
    })
    println("==================================================")
    //名调用
     def sayHi2(name: => String):Unit={
    println("函数调用")
      println(s"$name  hi")
      println(s"$name  hi")
    }
sayHi2({
  println("hello")
  "linhai"
})

运行结果的对比:

懒加载:

其实懒加载相当于Linux中的sleep函数   会暂时性休息,当使用到惰性语句的时候才会运行

关键字---lazy   而且lazy只能用于val关键字上

def sumxy(x:Int,y:Int):Int={
  println("sumxy调用")
  x+y
}
    lazy val sum=sumxy(10,20)
    println("啦啊啦啦啦")
    println(sum)

运行结果:

自定义while循环:

def mywhile(b:Boolean)(op : => Unit):Unit={
  if (b)
    {
      op
      mywhile(b)(op)
    }

}
var i=0
  mywhile(i<5)(
    {
      println(i)
      i +=1
    }
  )

上述代码会陷入死循环   因为传入b(i<5)的时候是值调用  只传参一次  一直为真则一直++

改进   对b进行名调用  

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

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

相关文章

【K8S系列】深入解析Pod对象(二)

目录 序言 1.Volume 简单介绍 2 Projected Volume 介绍 2.1 Secret 2.1.1 yaml讲解 2.1.2 创建Pod 2.2 Downward API 2.2.1 yaml示例 2.2.2 Downward API 支持字段 3 投票 序言 任何一件事情&#xff0c;只要坚持六个月以上&#xff0c;你都可以看到质的飞跃。 在…

SqlServer实用系统视图,你了解多少?

SqlServer实用系统视图&#xff0c;你了解多少&#xff1f;前言master..spt_valuessysdatabasessysprocesses一套组合拳sysobjectssys.all_objectssyscolumnssystypessyscommentssysindexes结束语前言 在使用任何数据库软件的时候&#xff0c;该软件都会提供一些可能不是那么公…

小规模容器编排使用Docker Swarm不香么,用个锤子的kubernetes

文章目录一、Docker Swarm是什么&#xff1f;二、Swarmkit和Swarm Mode是什么&#xff1f;三、Docker Swarm的核心设计四、Docker Swarm安装部署4.1、初始化Swarm节点14.2、新节点加入Swarm集群4.3、使用swarm部署服务4.4、swarm集群管理一、Docker Swarm是什么&#xff1f; D…

“QT 快速上手指南“ 之 计算器(二)组件,坐标,窗口

文章目录前言一、QT 基本组件用法介绍&#xff1a;1. QLabel &#xff1a;2. QPushButton :3. QLineEdit:二、坐标系统三、窗口部件的大小设置1. setSize( ) 函数&#xff1a;2. resize( )函数&#xff1a;3. setFixedSize( )函数:4. setFixedWidth( ) 和 setFixedHeight( )函数…

标准化归一化方法

一、经典机器学习的归一化算法 分别是0-1标准化&#xff08;Max-Min Normalization&#xff09;和Z-Score标准化。 1.1 0-1标准化方法 每一列中的元素减去当前列的最小值&#xff0c;再除以该列的极差。 不过在深度学习领域&#xff0c;我们更希望输入模型的数据是Zero-Ce…

使用Serv-U搭建FTP服务器并公网访问【内网穿透】

文章目录1. 前言2. 本地FTP搭建2.1 Serv-U下载和安装2.2 Serv-U共享网页测试2.3 Cpolar下载和安装3. 本地FTP发布3.1 Cpolar云端设置3.2 Cpolar本地设置4. 公网访问测试5. 结语1. 前言 科技日益发展的今天&#xff0c;移动电子设备似乎成了我们生活的主角&#xff0c;智能手机…

这些IT行业趋势,将改变2023

上一周&#xff0c;你被"AI"刷屏了吗&#xff1f; 打开任何一家科技媒体&#xff0c;人工智能都是不变的热门话题。周初大家还在用ChatGPT写论文、查资料、写代码&#xff0c;到周末的时候大家已经开始用GPT-4图像识别来做饭、Microsoft 365 Copilot 来写PPT了。 GP…

【周末闲谈】AI的旅途

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️周末闲谈】 系列目录 ✨第一周 二进制VS三进制 ✨第二周 文心一言&#xff0c;模仿还是超越&#xff1f; ✨第二周 畅想AR 文章目录系列目录前言AIAI的开端第一个AI程序AI的寒冬关于AI的思考末尾前言…

憨批的语义分割重制版11——Keras 搭建自己的HRNetV2语义分割平台

憨批的语义分割重制版11——Keras 搭建自己的HRNetV2语义分割平台学习前言什么是HRNetV2模型代码下载HRNetV2实现思路一、预测部分1、主干网络介绍a、Section-1b、Section-2c、Section-3d、Section-42、特征整合部分3、利用特征获得预测结果二、训练部分1、训练文件详解2、LOSS…

【Python童年游戏】满满的回忆杀—那些年玩过的童年游戏你还记得吗?那个才是你的菜?看到第一个我就泪奔了(致我们逝去的青春)

导语 滴一一学生卡&#x1f64c; 结伴上车的学生仔子们 用笑声打破车厢的沉默 大人眼里的晚高峰 是给放学后快乐&#x1f600;时光的加时 下车的学生匆匆起身带起 一阵熟悉的栀子香于&#x1f493; 是关于校园的记忆 开始零零散散地闪现 放学后集合的秘密基地/跟着城…

Half-UNet:用于医学图像分割的简化U-Net架构

Half-UNet简化了编码器和解码器&#xff0c;还使用了Ghost模块(GhostNet)。并重新设计的体系结构&#xff0c;把通道数进行统一。 论文动机 编码器的不同类型的架构图&#xff0c;编码器(A-C)的结构分别来源于U-Net的编码器、解码器和全的Unet结构。 下面是上图的一些结果指标…

4.2学习周报

文章目录前言文献阅读摘要介绍时间序列预测目前存在的问题时间序列预测方法分类未来方向时间序列预测总结前言 本周阅读文献《Forecast Methods for Time Series Data: A Survey》&#xff0c;本文主要对目前时间序列数据建模方法进行分类&#xff0c;主要分为了三类&#xff…

Linux->文件系统磁盘文件管理

目录 1 磁盘结构 2 逻辑抽象管理磁盘 2.1 逻辑抽象 2.2 管理磁盘 2.3 补充知识 3 软硬连接 1 磁盘结构 本篇的学习需要建立在大家在脑海中有一副磁盘的结构才能进行下去&#xff0c;所以我会以图解的方式为大家简单讲解一下&#xff0c;注&#xff1a;博主对这一部分并不是…

深度学习实战——卷积神经网络/CNN实践(LeNet、Resnet)

忆如完整项目/代码详见github&#xff1a;https://github.com/yiru1225&#xff08;转载标明出处 勿白嫖 star for projects thanks&#xff09; 系列文章目录 本系列博客重点在深度学习相关实践&#xff08;有问题欢迎在评论区讨论指出&#xff0c;或直接私信联系我&#xf…

详细介绍别人电脑访问到自己电脑运行的项目

文章目录 让别人远程访问你的代码网站项目或临时演示你的项目给客户的方式详解 引言一、创建一个你想要别人访问的项目二、明确你想要将这个网站或者项目存放的地方 终端分类服务器设备WEB服务器三、部署我们的网页 本地部署流程进入浏览器输入网址访问获取本机的IP地址&#…

多模态特征融合:图像、语音、文本如何转为特征向量并进行分类

多模态特征融合前言输入层&#xff0c;数据集转为特征向量图像语音什么是时域信号&#xff0c;什么是频域信号语音信号转换 - 1.傅立叶变换语音信号转换 - 2.梅尔频率倒谱系数文本词袋模型词嵌入模型输出层&#xff0c;多模态模型合并前言 学习多模态的话题可以从深度学习的分…

API接口安全—webservice、Swagger、WEBpack

API接口安全—webservice、Swagger、WEBpack1. API接口介绍1.1. 常用的API接口类1.1.1. API接口分类1.1.1.1. 类库型API1.1.1.2. 操作系统型API1.1.1.3. 远程应用型API1.1.1.4. WEB应用型API1.1.1.5. 总结1.1.2. API接口类型1.1.2.1. HTTP类接口1.1.2.2. RPC类接口1.1.2.3. web…

NLP与ChatGPT的碰撞:大模型和小模型联合发力

ChatGPT真的太火了&#xff01;作为NLP的终结者&#xff0c;ChatGPT又会与NLP发生怎么样的碰撞&#xff1f;大模型可以替代小模型吗&#xff1f;NLP又将何去何从&#xff1f;今天给大家推荐一本好书&#xff1a;《基于NLP的内容理解》&#xff01; 文章目录一、背景二、书籍介绍…

【原创】AIGC之ChatGPT工作原理

AIGC是什么 AIGC - AI Generated Content &#xff08;AI生成内容&#xff09;&#xff0c;对应我们的过去的主要是 UGC&#xff08;User Generated Content&#xff09;和 PGC&#xff08;Professional user Generated Content&#xff09;。 AIGC就是说所有输出内容是通过AI机…

2023年3月的10篇论文推荐

三月有很多的重大产品发布&#xff0c;包括刚刚发布的GPT4&#xff0c;还有Meta刚发布就被泄露的LLaMA&#xff0c;midjourney V5&#xff0c;还有ChatGPT的API&#xff08;非常便宜&#xff09;等等。 但是本文整理的是本月应该阅读的10篇论文&#xff0c;将包括多模态语言模…