【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.hqwc.cn/news/669786.html

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

相关文章

UE5(射线检测)学习笔记

这一篇会讲解射线检测点击事件、离开悬停、进入悬停事件的检测&#xff0c;以及关闭射线检测的事件&#xff0c;和射线检测蓝图的基础讲解。 创建一个简单的第三人称模板 创建一个射线检测的文件夹RadiationInspection&#xff0c;并且右键蓝图-场景组件-命名为BPC_Radiation…

React中的高阶组件的封装,高阶函数,HOC的含义及用法:

含义及作用: 高阶函数代码案例: 调用高阶组价:

自然语言(NLP)

It’s time for us to learn how to analyse natural language documents, using Natural Language Processing (NLP). We’ll be focusing on the Hugging Face ecosystem, especially the Transformers library, and the vast collection of pretrained NLP models. Our proj…

ubuntu20.04通过minio配置FTP服务

项目需求&#xff1a;原来存储文件用的是oss服务存储的&#xff0c;本地minio服务。因为项目需求需要ftp服务来访问文件。查看了一下minio官网4.20版本以后的支持ftp服务。官网介绍如下&#xff1a; 参考文章地址如下&#xff1a;File Transfer Protocol (FTP/SFTP) — MinIO …

读天才与算法:人脑与AI的数学思维笔记19_深度数学

1. 深度数学 1.1. 组合与选择&#xff0c;是发明新事物的两个不可或缺的条件 1.1.1. 保尔瓦雷里&#xff08;Paul Valry&#xff09; 1.2. 利用以往的数学定理证明过程训练算法&#xff0c;以发现新的定理 1.3. 谷歌设在伦敦的总部整体有一种现代牛津大学的感觉&#xff0c…

Ubuntu20.04右键打不开终端

今天用virtualbox安装了ubuntu20.04 问题&#xff1a;右键打开终端&#xff0c;怎么也打开不了&#xff01; 点了也没反应&#xff0c;或者鼠标转小圈圈&#xff0c;然后也没有反应… 解决方法&#xff1a; 1、Ctrl Alt F6 先切换到终端访问界面 mac电脑 Ctrl Alt F6 …

人工智能,破0认知

认识人工智能&#xff08;AI) 一直以来&#xff0c;对人工智能都没有一个整体的学习和认知&#xff0c;作为最火的一门技术&#xff0c;平常的工作中也经常用到、也经常见到很多同学都在使用人工智能写文章、修代码。现在人工智能已经深刻影响到工作和生活中的方方面面&#x…

解决pycharm关闭项目时一直显示正在关闭项目(解决pycharm在此窗口打开项目卡死的问题)

文章目录 💢 问题 💢🏡 演示环境 🏡💢 问题 💢 开发者们在日常工作中离不开各种强大的IDE(集成开发环境),其中PyCharm以其丰富的功能和友好的界面赢得了众多Python开发者的青睐。然而,你是否曾遇到过这样的问题:当你试图关闭PyCharm时(或在此窗口打开项目),…

HNU-人工智能-实验2-简单CSP问题

人工智能-实验2 计科210x 甘晴void 一、实验目的 求解约束满足问题 使用回溯搜索算法求解八皇后问题 二、实验平台 课程实训平台https://www.educoder.net/paths/369 三、实验内容 3.0 题目要求 回溯搜索算法 搜索与回溯是计算机解题中常用的算法&#xff0c;很多问…

实力登榜!蓝卓入选2024中国未来独角兽TOP100企业

日前&#xff0c;由民建中央、中国科协指导&#xff0c;民建浙江省委会、中国投资发展促进会联合主办的第八届万物生长大会中国未来独角兽大会在杭州举办。 会上&#xff0c;《2024中国未来独角兽TOP100榜单》隆重揭晓。其中&#xff0c;蓝卓在全国参评企业中脱颖而出&#xff…

CNN模型

CNN 卷积网络 输入层&#xff1a;是一张像素图片 h高 * w宽 * c c是通道数&#xff0c;rgb是3通道 把图像分割&#xff0c;每一块 卷积层Conv&#xff1a;提取特征&#xff0c;发现边缘、方向等信息 卷积核&#xff1a;每块像素 和卷积核 相乘 获取边缘信息 一般选择1x1…

每日OJ题_DFS解决FloodFill⑦_力扣LCR 130. 衣橱整理(原剑指Offer13机器人的运动范围)

目录 力扣LCR 130. 衣橱整理&#xff08;原剑指Offer13机器人的运动范围&#xff09; 解析代码 力扣LCR 130. 衣橱整理&#xff08;原剑指Offer13机器人的运动范围&#xff09; LCR 130. 衣橱整理 难度 中等 家居整理师将待整理衣橱划分为 m x n 的二维矩阵 grid&#xff…