【Scala---04】函数式编程 『 函数 vs 方法 | 函数至简原则 | 函数式编程』

文章目录

  • 1. 函数 vs 方法
    • 1.1 方法
      • (1) 定义方法
      • (2) 运算符即方法
    • 1.2 函数
      • (1) 定义函数
      • (2) 匿名函数
    • 1.3 方法转为函数
    • 1.4 可变参数&默认参数
  • 2. 函数至简原则
  • 3. 函数式编程
    • 3.1 函数式编程思想
    • 3.3 函数柯里化&闭包
    • 3.5 递归 & 尾递归
  • 4. 补充
    • 4.1 访问元祖元素
    • 4.2 =>的含义
    • 4.3 下划线的使用总结

1. 函数 vs 方法

在Java中方法与函数没区别,但是在Scala中方法和函数是不一样的。Java是面向对象的,Scala是面向函数式编程的,主要体现在如下4点:

Java对象可以作为一个值传递对象可以作为参数传递对象可以作为返回值传递可以调用对象
Scala函数可以作为一个值传递函数可以作为参数传递函数可以作为返回值传递可以调用函数
Scala方法不可以作为一个值传递方法不可以作为参数传递方法不可以作为返回值传递可以调用函数

可以看出Scala中函数比方法更加强大,而函数相比于方法最重要的功能就是函数能作为参数传递,也就是说a和b进行的操作不是写死的,而是可变的。

  • 从位置上理解:方法 只能在类中定义,做为类的属性;函数 可以在任何地方定义。
  • 从是否可以重载的角度:方法定义在类中可以实现重载;函数不可以重载。
  • 从运行位置角度:方法是保存在方法区;函数是保存在堆中。

1.1 方法

(1) 定义方法

定义方法语法如下:

object 类名 {def 方法名([变量:变量类型,变量:变量类型]):返回值类型 = {方法体}
}

比如:
在这里插入图片描述

  1. 方法不能作为值传递

    object Main {def main(args: Array[String]): Unit = {def add(x:Int, y:Int):Int = {x + y}val result = add   // 会报错println(result)}
    }
    
  2. 方法不能作为参数传递

    object Main {def main(args: Array[String]): Unit = {// 1. 定义calculate方法def calculate(x: Int, y: Int, func: (Int, Int) => Int): Int = { // x与y进行func操作,这个func函数需要指名 形参类型和返回值func(x, y)}// 2. 定义add方法def add(x:Int, y:Int):Int = {x + y}// 3. 函数作为参数传递val result = calculate(2, 3, add) // 不会报错,自动转为函数传递println(result)}
    }
    
  3. 方法不能作为返回值传递

    object Main {def main(args: Array[String]): Unit = {// 1. 定义getFunc方法def getFunc() = { // x与y进行func操作,这个func函数需要指名 形参类型和返回值def func(x: Int, y: Int) = {x + y} func  // 会报错}// 2. 得到函数println(getFunc())}
    }
    
  4. 方法可以直接调用

    object Main {def main(args: Array[String]): Unit = {def add(x: Int, y: Int) = x + yprintln(add(2, 3)) // 输出:5}
    }

(2) 运算符即方法

  1. 所有的运算符本质上是方法。比如查看Int
    在这里插入图片描述
    可以看到类中定义了很多以运算符命名的方法
    在这里插入图片描述
    因此,以下两种方法是等价的
     val a = 1 + 2val a = 1.+(2)
    
  2. 反过来,可以定义这样的方法,并调用
    1. 例子1

      object Cal {def say(x:Int):Int = x
      }object Main {def main(args: Array[String]): Unit = {// 1. 用 类.方法名(参数列表) 形式调用方法var result1 = Cal.say(3)// 2. 用 类 方法 参数列表 形式调用方法var result2 = Cal say (3)  var result3 = Cal say 3    // 如果参数列表只有一个值,括号是可以省略的}
      }
      
    2. 例子2

      object Main {def say(x:Int):Int = xdef main(args: Array[String]): Unit = {// 1. 用 类.方法名(参数列表) 形式调用方法var result1 = this.say(3)// 2. 用 类 方法 参数列表 形式调用方法var result2 = this say (3)  // 如果参数列表只有一个值,括号是可以省略的var result3 = this say 3}
      }
      

1.2 函数

(1) 定义函数

Scala中有23个函数接口类,函数的本质就是实现这些接口类来实现强大的功能:
在这里插入图片描述

  1. Function0:无参数,无返回值
  2. Function1:…

定义函数语法如下:

object 类名 {def 函数名:([变量类型,变量类型])=>返回值类型 = ([变量:变量类型,变量:变量类型]) => {方法体}
}

比如:
在这里插入图片描述

  1. 函数可以作为一个值传递

    object Main {def main(args: Array[String]): Unit = {val add = (x:Int, y:Int) => x + yval result = add   // 不会报错println(result) }
    }
    
  2. 函数可以作为参数传递,此时需要指名函数的类型。格式为:(参数类型)=>返回值类型

    object Main {def main(args: Array[String]): Unit = {// 1. 定义calculate方法def calculate(x:Int, y:Int, func:(Int, Int)=>Int): Int = { // x与y进行func操作,这个func函数需要指名 形参类型和返回值func(x, y)}// 2. 定义add函数def add = (x:Int, y:Int) => x + y// 3. 函数作为参数传递val result = calculate(2, 3, add)// 4. 输出println(result)  // 输出5}
    }
    
  3. 函数可以作为返回值传递

    object Main {def main(args: Array[String]): Unit = {// 1. 定义getFunc方法def getFunc() = { // x与y进行func操作,这个func函数需要指名 形参类型和返回值val func = (x:Int, y:Int) => x + yfunc}// 2. 得到函数println(getFunc())// 3. 得到函数并执行函数println(getFunc()(2, 3))  // 输出5}
    }
    
  4. 函数可以执行

    object Main {def main(args: Array[String]): Unit = {val add = (x:Int, y:Int) => x + yprintln(add(2, 3))}
    }
    

(2) 匿名函数

匿名函数与函数的语法区别就在于前者是val关键字,后者是def关键字。比如:
在这里插入图片描述
匿名函数简化了函数值传递:
在这里插入图片描述

注意:这只会定义一个函数,也不会执行函数这点和Java不一样,java的lambda表达式是会创建对象,并执行构造方法。

1.3 方法转为函数

  1. 通用转换方式,在方法名后面 + 空格 + _ 即可,语法为:方法名 _

    object Main {def main(args: Array[String]): Unit = {def add(x:Int, y:Int):Int = {x + y}val result = add _     // 将方法转为函数println(result(2, 3))  // 输出:5}
    }
    
  2. 在参数处将方法转为函数时,可以简化,去掉 _,直接方法名

    object Main {def main(args: Array[String]): Unit = {// 1. 定义calculate方法def calculate(x: Int, y: Int, func: (Int, Int) => Int): Int = { // x与y进行func操作,这个func函数需要指名 形参类型和返回值func(x, y)}// 2. 定义add函数def add(x:Int, y:Int):Int = {x + y}// 3. 函数作为参数传递val result1 = calculate(2, 3, add _)      // 此时可优化,去掉 空格_val result2 = calculate(2, 3, add)  // 优化后的代码}
    }
    

1.4 可变参数&默认参数

object Test03_FunArgs {def main(args: Array[String]): Unit = {// (1)可变参数:在类型后面加*号def sayHi(names:String*):Unit = {println(s"hi $names")}sayHi()sayHi("linhai")sayHi("linhai","jinlian")// (2)可变参数必须在参数列表的最后def sayHi1(sex: String,names:String*):Unit = {println(s"hi $names")}// (3)参数默认值def sayHi2(name:String = "linhai"):Unit = {println(s"hi ${name}")}sayHi2("linhai")sayHi2()// (4)默认值参数在使用的时候 可以不在最后def sayHi3( name:String = "linhai" , age:Int):Unit = {println(s"hi ${name}")}// (5)带名参数:指调用方法时,指定传参顺序sayHi3(age = 10, name = "niu")}
}

2. 函数至简原则

在这里插入图片描述

注意:方法最后一行的return可以省略,但是除此之外都不能省略。比如
在这里插入图片描述

object Test04_FuncSimply {def main(args: Array[String]): Unit = {//(1)return可以省略,Scala会使用方法体的最后一行代码作为返回值def func1(x: Int, y: Int): Int = {x + y}// (2)如果方法体只有一行代码,可以省略花括号def func2(x: Int, y: Int): Int = x + y//(3)返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起省略)//     此时,函数就变为了数学表达式的形式:f(x, y) = x + ydef func3(x: Int, y: Int) = x + y//(4)如果有return,则不能省略返回值类型,必须指定def func4(x: Int, y: Int): Int = {if (x < 20) {return x + y}2 * x + 3 * y}//(5)如果方法明确声明unit,那么即使函数体中使用return关键字也不起作用def func5(x: Int, y: Int): Unit = return x + y//(6)Scala如果期望是无返回值类型,可以省略等号def func6(x: Int, y: Int) {println(x + y)}// (7)如果方法无参,但是声明了参数列表,那么调用时,小括号,可加可不加def func7(): Unit = {println("hello")}// (8)如果方法没有参数列表,那么小括号可以省略,调用时小括号必须省略def func8 {println("hello")}// (9)如果不关心函数名,只关心映射逻辑,就会变为lambda表达式(x:Int, y:Int) => {println(x + y)}val func = (x:Int, y:Int) => {println(x + y)}  // 如果要设置函数名可以这样。此时,func就是函数名}
}

3. 函数式编程

3.1 函数式编程思想

  1. 函数式编程思想:① 当做数学题,y = f(x),重要的是映射关系。② 使用val,在分布式上计算后不会产生歧义
  2. 通过前面可以知道,定义函数有3种形式:
    1. 方法转函数。先定义方法,再方法名 _
    2. 直接定义函数def
    3. 匿名函数
      在这里插入图片描述

一看到 => 或 一看到 _,就要想到这是表示函数。

3.3 函数柯里化&闭包

  • 闭包:内层函数用到了外层函数变量,如果直接调用内层函数会取不到外层函数的这个变量值。此时,内层函数(万物皆对象,函数也是对象)的堆中的对象会保留一份引用到外层函数的值。
    闭包参考链接

  • 函数柯里化:将一个接收多个参数的函数转化成一个一个接受参数的函数过程,可以简单的理解为一种特殊的参数列表声明方式。函数柯里化

    object TestFunction {val sum = (x: Int, y: Int, z: Int) => x + y + z// 函数柯里化的底层逻辑:本质是将函数作为返回值val sum1 = (x: Int) => {y: Int => {  // 匿名函数z: Int => { // 匿名函数x + y + z}}}// 函数柯里化的另一种简单表达val sum2 = (x: Int) => (y: Int) => (z: Int) => x + y + z// 方法也有函数柯里化def sum3(x: Int)(y: Int)(z: Int) = x + y + zdef main(args: Array[String]): Unit = {sum(1, 2, 3)sum1(1)(2)(3) // sum1(1)调用完后,返回一个函数; sum1(1)(2)是调用返回的函数; .......sum2(1)(2)(3)sum3(1)(2)(3)}
    }
    

3.5 递归 & 尾递归

  1. 递归与Java中的递归一样:前面知道scala的方法返回值是可以省略的,默认分配返回值类型,但是 如果方法是递归方法,则必须指定方法的返回值类型,否则会报错

    object Test{def main(args: Array[String]): Unit = {// 实现阶乘def fact(n : Int) : Int = {  // 必须指名方法的返回值类型// 跳出递归if(n == 1) return 1// 递归逻辑n * fact(n - 1)}// 调用阶乘方法println(fact(5))}
    }
    
  2. 尾递归:递归是将每次调用函数/方法会压入到栈中,是累计使用资源,容易造成栈溢出;而尾递归是覆盖使用资源,不会造成栈溢出。所以,尾递归资源利用率更加高。尾递归参考链接

    一般支持函数式编程语言都支持尾递归;但是Java不支持尾递归。

4. 补充

4.1 访问元祖元素

变量名._数字    
比如:x._1 表示访问x的第一个元素

4.2 =>的含义

https://blog.csdn.net/qq_43546676/article/details/130992479

4.3 下划线的使用总结

https://blog.csdn.net/qq_43546676/article/details/130874779

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

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

相关文章

ROS机器人入门:机器人系统仿真【学习记录】——2

承接上一篇博客&#xff1a; ROS机器人入门&#xff1a;机器人系统仿真【学习记录】——1-CSDN博客 我们先前结束了&#xff08;上一篇博客中&#xff09;&#xff1a; 1. 概述 2. URDF集成Rviz基本流程 3. URDF语法详解 4. URDF优化_xacro 下面让我们继续学习ROS机器人…

【Scala---01】Scala简介与环境部署『 Scala简介 | 函数式编程简介 | Scala VS Java | 安装与部署』

文章目录 1. Scala简介2. 函数式编程简介3. Scala VS Java4. 安装与部署 1. Scala简介 Scala是由于Spark的流行而兴起的。Scala是高级语言&#xff0c;Scala底层使用的是Java&#xff0c;可以看做是对Java的进一步封装&#xff0c;更加简洁&#xff0c;代码量约是Java的一半。…

前端开发攻略---打破Chrome的最小字号限制,设置任意字号大小

目录 1、原因 2、解决方法 1、原因 由于Chrome浏览器的限制&#xff0c;在网页中的字号默认最小为12px&#xff0c;更改为12px以下的字号大小是无效的 2、解决方法 1、在Chrome浏览器中调整字号最小值 优点&#xff1a;快&#xff0c;方便&#xff0c; 缺点&#xff1a;只对自…

Delta lake with Java--在spark集群上运行程序

昨天写了第一篇入门&#xff0c;今天看见有人收藏&#xff0c;继续努力学习下去。今天要实现的内容是如何将昨天的HelloDetlaLake 在spark集群上运行&#xff0c;。具体步骤如下 1、安装spark,我使用的是 spark-3.5.1-bin-hadoop3-scala2.13&#xff0c;去官网下载&#xff0c…

全流程基于GIS、python机器学习技术的地质灾害风险评价与信息化建库应用

入门篇&#xff0c;ArcGIS软件的快速入门与GIS数据源的获取与理解&#xff1b;方法篇&#xff0c;致灾因子提取方法、灾害危险性因子分析指标体系的建立方法和灾害危险性评价模型构建方法&#xff1b;拓展篇&#xff0c;GIS在灾害重建中的应用方法&#xff1b;高阶篇&#xff1…

网络基础-思科IOS基本操作(Cisco)

思科设备的命令行模式&#xff1a; 1.用户模式 (User EXEC Mode): 这是用户最初进入设备时所处的模式。在这个模式下&#xff0c;用户只能执行一些基本的查看命令&#xff0c;不能进行任何配置更改。能够进入该模式说明设备没问题&#xff1b;提示符通常是一个设备名称后面跟着…

BetterMouse for Mac激活版:鼠标增强软件

BetterMouse for Mac是一款鼠标增强软件&#xff0c;旨在取代笨重的、侵入性的和耗费资源的鼠标驱动程序&#xff0c;如罗技选项。它功能丰富&#xff0c;重量轻&#xff0c;效率优化&#xff0c;而且完全隐私安全&#xff0c;试图满足你在MacOS上使用第三方鼠标的所有需求。 B…

【linux学习指南】linux 环境搭建

文章目录 &#x1f4dd;前言&#x1f320; 云服务器的选择&#x1f320;阿里云&#x1f320;腾讯云&#x1f320;华为云 &#x1f320;使用 XShell 远程登陆到 Linux&#x1f309;下载 XShell &#x1f320;查看 Linux 主机 ip&#x1f309; XShell 下的复制粘贴&#x1f309; …

Java 函数式编程 的基础使用2-BiConsumer

1、创建函数时&#xff0c;确定函数的参数类型和具体操作。 2、使用accept接收函数参数&#xff0c;并执行函数操作。 public class MyBiConsumer {public static void main(String[] args) {BiConsumer<String, Integer> printNameAndAge (param1, param2) -> {Sys…

FIFO Generate IP核使用——异步复位

FIFO Generator IP核提供了一个复位输入&#xff0c;当该输入被激活时&#xff0c;它会复位所有的计数器和输出寄存器。对于块RAM或分布式RAM实现&#xff0c;复位FIFO并不是必需的&#xff0c;可以在FIFO中禁用复位引脚。共有两种复位类型选项&#xff1a;异步复位和同步复位。…

FTP和NFS

一、FTP 1.FTP原理 FTP&#xff08;file Transfer Protocol&#xff0c;文件传输协议&#xff09;&#xff0c;是典型的C/S架构的应用层协议&#xff0c;由客户端软件和服务端软件两个部分共同实现文件传输功能&#xff0c;FTP客户端和服务器之间的连接时可靠的&#xff0c;面…

八股文(C#篇)

C#中的数值类型 堆和栈 值类型的数据被保存在栈&#xff08;stack)上&#xff0c;而引用类型的数据被保存在堆&#xff08;heap&#xff09;上&#xff0c;当值类型作为参数传递给函数时&#xff0c;会将其复制到新的内存空间中&#xff0c;因此在函数中对该值类型的修改不会影…

数据结构===二叉树

文章目录 概要二叉树的概念分类存储遍历前序中序后序 小结 概要 简单写下二叉树都有哪些内容&#xff0c;这篇文章要写什么 二叉树的概念分类&#xff0c;都有哪些二叉树遍历 对一个数据结构&#xff0c;最先入手的都是定义&#xff0c;然后才会有哪些分类&#xff0c;对二叉…

时代少年团MV女主被骂上热搜,时代峰峻走到了十字路口

女演员和男团拍个MV都会被骂上热搜&#xff0c;这年头粉丝都这么霸道了&#xff1f; #时代少年团女主 贺美琦# #贺美琦曾是TFBOYS的MV女主# #时代少年团MV有女主# ...... 自从时代少年团第三张专辑《叁重楼》的新歌《那些我没说的话》曝光之后&#xff0c;歌曲MV中女主角的…

开源电子邮件营销平台 listmonk 使用教程

做产品肯定要做电子邮件营销&#xff0c;特别是面向海外的产品&#xff0c;电子邮件营销已成为企业与客户沟通、建立品牌忠诚度和推动销售的重要工具&#xff0c;可以直接接触到目标受众&#xff0c;提供个性化内容&#xff0c;并以相对较低的成本获得可观的投资回报。你看&…

Vue2——前端笔记

Vue 一、Vue核心1.1、vue简介1.2、初始vue1.3、模板语法1.4、数据绑定1.5、el与data的两种写法1.6、MVVM模型1.7、Vue中的数据代理1.7.1、Object.defineProperty() 理解1.7.2、Vue中的数据代理 1.8、事件处理1.8.1、事件的基本用法1.8.2、事件修饰符1.8.3、键盘事件 1.9、计算属…

KUKA机器人KR3 R540维护保养——更换齿形带

对KUKA机器人进行维护保养&#xff0c;可以增加机器人的使用寿命&#xff0c;减少故障率。本篇文章的内容是更换KUKA机器人轴齿形带。我们知道机器人长时间运行后&#xff0c;部分轴的齿形带会发生磨损&#xff0c;张力也会发生变化&#xff0c;这时就需要更换齿形带。本篇文章…

RoNID:通过生成可靠标签与聚类友好型表征来实现新意图的发现

论文地址&#xff1a;https://arxiv.org/abs/2404.08977 原文地址&#xff1a;intents-are-not-going-away-ronid-is-a-new-intent-discovery-framework 2024 年 4 月 26 日 Robust New Intent Discovery&#xff08;RoNID&#xff09;框架致力于在开放域场景中识别已知意图并合…

【STM32+HAL】DS18B20读取环境温度

一、准备工作 有关CUBEMX的初始化配置&#xff0c;参见我的另一篇blog&#xff1a;【STM32HAL】CUBEMX初始化配置 二、所用工具 1、芯片&#xff1a; STM32F407VET6 2、IDE&#xff1a; MDK-Keil软件 3、库文件&#xff1a;STM32F4xxHAL库 三、实现功能 串口打印当前温度值…

羊毛项目(华为iPhone茅台),讲解抢购渠道与抢购注意事项

薅羊毛天花板&#xff0c;华为iPhone茅台无脑撸&#xff0c;几分钟换几百元(非脚本项目) 网盘自动获取 链接&#xff1a;https://pan.baidu.com/s/1lpzKPim76qettahxvxtjaQ?pwd0b8x 提取码&#xff1a;0b8x