前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >04.Scala:高阶函数、隐式转换

04.Scala:高阶函数、隐式转换

作者头像
Maynor
发布于 2021-04-09 07:56:41
发布于 2021-04-09 07:56:41
95200
代码可运行
举报
运行总次数:0
代码可运行

Scala:高阶函数、隐式转换

课程目标

  • 理解高阶函数的概念(作为值的函数、匿名函数、闭包、柯里化)
  • 掌握隐式转换和隐式参数
  • 掌握Akka并发编程框架

1. 高阶函数

scala 混合了面向对象和函数式的特性,在函数式编程语言中,函数是“头等公民”,它和Int、String、Class等其他类型处于同等的地位,可以像其他类型的变量一样被传递和操作。

高阶函数包含

  • 作为值的函数
  • 匿名函数
  • 闭包
  • 柯里化等等

1.1 作为值的函数

在scala中,函数就像和数字、字符串一样,可以将函数传递给一个方法。我们可以对算法进行封装,然后将具体的动作传递给方法,这种特性很有用。

我们之前学习过List的map方法,它就可以接收一个函数,完成List的转换。

示例

示例说明

将一个整数列表中的每个元素转换为对应个数的小星星

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
List(1, 2, 3...) => *, **, *** 

步骤

  1. 创建一个函数,用于将数字装换为指定个数的小星星
  2. 创建一个列表,调用map方法
  3. 打印转换为的列表

参考代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
val func: Int => String = (num:Int) => "*" * num

println((1 to 10).map(func))

1.2 匿名函数

定义

上面的代码,给(num:Int) => “*” * num函数赋值给了一个变量,但是这种写法有一些啰嗦。在scala中,可以不需要给函数赋值给变量,没有赋值给变量的函数就是匿名函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
val list = List(1, 2, 3, 4)

// 字符串*方法,表示生成指定数量的字符串
val func_num2star = (num:Int) => "*" * num

print(list.map(func_num2star))

示例

使用匿名函数优化上述代码

参考代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
println((1 to 10).map(num => "*" * num))
// 因为此处num变量只使用了一次,而且只是进行简单的计算,所以可以省略参数列表,使用_替代参数
println((1 to 10).map("*" * _))

1.3 柯里化

在scala和spark的源代码中,大量使用到了柯里化。为了后续方便阅读源代码,我们需要来了解下柯里化。

定义

柯里化(Currying)是指将原先接受多个参数的方法转换为多个只有一个参数的参数列表的过程。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ks3Do46E-1617760738513)(/assets/1552811606951.png)]

柯里化过程解析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rfwAX73E-1617760738515)(assets/1552811639044.png)]

示例

示例说明

  • 编写一个方法,用来完成两个Int类型数字的计算
  • 具体如何计算封装到函数中
  • 使用柯里化来实现上述操作

参考代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 柯里化:实现对两个数进行计算
def calc_carried(x:Double, y:Double)(func_calc:(Double, Double)=>Double) = {
    func_calc(x, y)
}

def main(args: Intrray[String]): Unit = {
    println(calc_carried(10.1, 10.2){
        (x,y) => x + y
    })
    println(calc_carried(10, 10)(_ + _))
    println(calc_carried(10.1, 10.2)(_ * _))
    println(calc_carried(100.2, 10)(_ - _))
}

1.4 闭包

闭包其实就是一个函数,只不过这个函数的返回值依赖于声明在函数外部的变量。

可以简单认为,就是可以访问不在当前作用域范围的一个函数。

示例一

定义一个闭包

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
val y=10

val add=(x:Int)=>{
    x+y
}

println(add(5)) // 结果15

add函数就是一个闭包

示例二

柯里化就是一个闭包

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  def add(x:Int)(y:Int) = {
    x + y
  }

上述代码相当于

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  def add(x:Int) = {
    (y:Int) => x + y
  }

2. 隐式转换和隐式参数

隐式转换和隐式参数是scala非常有特色的功能,也是Java等其他编程语言没有的功能。我们可以很方便地利用隐式转换来丰富现有类的功能。后面在编写Akka并发编程、Spark SQL、Flink都会看到隐式转换和隐式参数的身影。

2.1 定义

所谓隐式转换,是指以implicit关键字声明的带有单个参数的方法。它是自动被调用的,自动将某种类型转换为另外一种类型。

使用步骤

  1. 在object中定义隐式转换方法(使用implicit)
  2. 在需要用到隐式转换的地方,引入隐式转换(使用import)
  3. 自动调用隐式转化后的方法

示例

示例说明

使用隐式转换,让File具备有read功能——实现将文本中的内容以字符串形式读取出来

步骤

  1. 创建RichFile类,提供一个read方法,用于将文件内容读取为字符串
  2. 定义一个隐式转换方法,将File隐式转换为RichFile对象
  3. 创建一个File,导入隐式转换,调用File的read方法

参考代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class RichFile(val file:File) {
    // 读取文件为字符串
    def read() = {
        Source.fromFile(file).mkString
    }
}

object RichFile {
    // 定义隐式转换方法
    implicit def file2RichFile(file:File) = new RichFile(file)
}

def main(args: Array[String]): Unit = {
    // 加载文件
    val file = new File("./data/1.txt")

    // 导入隐式转换
    import RichFile.file2RichFile

    // file对象具备有read方法
    println(file.read())
}

2.2 隐式转换的时机

  • 当对象调用类中不存在的方法或者成员时,编译器会自动将对象进行隐式转换
  • 当方法中的参数的类型与目标类型不一致时

2.3 自动导入隐式转换方法

前面,我们手动使用了import来导入隐式转换。是否可以不手动import呢?

在scala中,如果在当前作用域中有隐式转换方法,会自动导入隐式转换。

示例:将隐式转换方法定义在main所在的object中

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class RichFile(val f:File) {
  // 将文件中内容读取成字符串
  def read() = Source.fromFile(f).mkString
}

object ImplicitConvertDemo {
  // 定义隐式转换方法
  implicit def file2RichFile(f:File) = new RichFile(f)

  def main(args: Array[String]): Unit = {
    val f = new File("./data/textfiles/1.txt")

    // 调用的其实是RichFile的read方法
    println(f.read())
  }
}

2.4 隐式参数

方法可以带有一个标记为implicit的参数列表。这种情况,编译器会查找缺省值,提供给该方法。

定义

  1. 在方法后面添加一个参数列表,参数使用implicit修饰
  2. 在object中定义implicit修饰的隐式值
  3. 调用方法,可以不传入implicit修饰的参数列表,编译器会自动查找缺省值

[!NOTE]

  1. 和隐式转换一样,可以使用import手动导入隐式参数
  2. 如果在当前作用域定义了隐式值,会自动进行导入

示例

示例说明

  • 定义一个方法,可将传入的值,使用一个分隔符前缀、后缀包括起来
  • 使用隐式参数定义分隔符
  • 调用该方法,并打印测试

参考代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 使用implicit定义一个参数
def quote(what:String)(implicit delimiter:(String, String)) = {
    delimiter._1 + what + delimiter._2
}

// 隐式参数
object ImplicitParam {
    implicit val DEFAULT_DELIMITERS = ("<<<", ">>>")
}

def main(args: Array[String]): Unit = {
	// 导入隐式参数
    import ImplicitParam.DEFAULT_DELIMITERS

    println(quote("李雷和韩梅梅"))
}

elimiter:(String, String)) = { delimiter._1 + what + delimiter._2 }

// 隐式参数 object ImplicitParam { implicit val DEFAULT_DELIMITERS = ("<<<", “>>>”) }

def main(args: Array[String]): Unit = { // 导入隐式参数 import ImplicitParam.DEFAULT_DELIMITERS

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
println(quote("李雷和韩梅梅"))

}

代码语言:javascript
代码运行次数:0
运行
复制
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/04/07 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
2021年大数据常用语言Scala(三十七):scala高级用法 高阶函数用法
Scala 混合了面向对象和函数式的特性,在函数式编程语言中,函数是“头等公民”,它和Int、String、Class等其他类型处于同等的地位,可以像其他任何数据类型一样被传递和操作。
Lansonli
2021/10/11
5290
scala快速入门系列【高阶函数】
本篇作为scala快速入门系列的第三十六篇博客,为大家带来的是关于高阶函数的内容。
大数据梦想家
2021/01/26
4370
scala快速入门系列【高阶函数】
Scala专题系列(七):高阶函数
val num = 2.2 val fun = scala.math.ceil _
用户5252199
2022/04/18
4140
Scala的函数
----------目录--------------------------------------------------------- 1.Scala简介和安装 2.Scala语法介绍 3.Scala的函数 4.Scala中的集合类型 ------------------------------------------------------------------------------------------------------------- Scala的函数 1、函数的声明     scala
云飞扬
2018/05/11
1.4K0
Scala 学习笔记之高阶函数
Scala混合了面向对象和函数式的特性.在函数式编程语言中,函数可以像任何其他数据类型一样被传递和操作.如果想要给算法传入明细动作时,只需要将明细动作包在函数当中作为参数传入即可.
smartsi
2019/08/07
6800
Scala语言入门:初学者的基础语法指南
作为一种在Java虚拟机(JVM)上运行的静态类型编程语言,Scala结合了面向对象和函数式编程的特性,使它既有强大的表达力又具备优秀的型态控制。
BookSea
2023/10/13
3710
2021年大数据常用语言Scala(三十八):scala高级用法 隐式转换和隐式参数
隐式转换和隐式参数是scala非常有特色的功能,也是Java等其他编程语言没有的功能。我们可以很方便地利用隐式转换来丰富现有类的功能。
Lansonli
2021/10/11
5950
scala的隐式转换学习总结(详细)
1) 隐式转换函数的函数名可以是任意的,与函数名称无关,只与函数签名(函数参数和返回值类型)有关。
全栈程序员站长
2022/11/07
7380
大数据开发语言scala:源于Java,隐式转换秒杀Java
在多年的学习路上,也掌握了几门比较常见的语言,例如Java、Python以及前端Vue生态中包含的语言。很多时候,各种语言相似功能的框架都会被放在一起比较,来评判语言本身的优劣。
叫我阿柒啊
2024/06/21
2570
大数据开发语言scala:源于Java,隐式转换秒杀Java
Scala语法基础之隐式转换
一,简介 从类型S到类型T的隐式转换由具有函数类型S => T的隐式值定义,或者通过可转换为该类型的值的隐式方法来定义。隐含转换适用于两种情况: 1),如果表达式e是类型S,并且S不符合表达式的期望类型T. 2),在具有类型S的e的e.m表达中,如果m不表示S的成员 在第一种情况下,搜索适用于e并且其结果类型符合T的转换c。在第二种情况下,搜索适用于e的转换c,其结果包含名为m的成员。 列表[Int]的两个列表xs和ys的以下操作是合法的: xs <= ys 前提是下面定义的隐式方法list2ordered
Spark学习技巧
2018/01/30
1.2K0
Scala语法基础之隐式转换
不可不会的scala隐式转换
从类型S到类型T的隐式转换由具有函数类型S => T的隐式值定义,或者通过可转换为该类型的值的隐式方法来定义。隐含转换适用于两种情况:
Spark学习技巧
2021/03/05
7360
不可不会的scala隐式转换
scala 隐式转换
Scala 中可以让函数库调用变得更加方便的隐式变换和隐式参数,以及如何通过它们来避免一些繁琐和显而易见的细节问题。 内容主要包括 implicits 的使用规则、隐含类型转换、转换被方法调用的对象等
全栈程序员站长
2022/11/10
1.1K0
Scala 隐式转换简明教程
对于 Spark 开发者来说 Scala 终究是个绕不过去的坎, 而 对于 Scala ,隐式转换终究也是一个绕不过去的坎。 所以本文就以一种尽可能简单的方式带大家来理解一下 Scala 的隐式转换。
solve
2019/10/30
6910
Scala教程之:静态类型
Scala是静态类型的,它拥有一个强大的类型系统,静态地强制以安全、一致的方式使用抽象,我们通过下面几个特征来一一说明:
程序那些事
2020/07/07
1.3K0
Spark基础-scala学习(八、隐式转换与隐式参数)
大纲 隐式转换 使用隐式转换加强现有类型 导入隐式转换函数 隐式转换的发生时机 隐式参数 隐式转换 要实现隐式转换,只要程序可见的范围内定义隐式转换函数即可。Scala会自动使用隐式转换函数。隐式转换函数与普通函数唯一的语法区别就是,要以implicit开头,而且一定要定义函数返回类型 案例:特殊售票窗口(只接受特殊人群,比如学生、老人等) scala> :paste // Entering paste mode (ctrl-D to finish) class SpecialPerson(val nam
老梁
2019/09/10
1.3K0
隐式转换函数_隐函数可以转化为显函数
隐式转换函数(implicit conversion function)是以implicit关键字声明的带有单个参数的函数,这样的函数将被自动应用,将值从一种类型转换为另一种类型。隐式转换函数叫什么名字是无所谓的,因为通常不会由用户手动调用,而是由Scala进行调用。但是如果要使用隐式转换,则需要对隐式转换函数进行导入。因此通常建议将隐式转换函数的名称命名为“one2one”的形式。 scala会考虑如下位置的隐式转换函数:
全栈程序员站长
2022/09/27
8470
Scala 高阶(十一):隐式转换和泛型
在Scala中有一种特殊的机制,当编译器第一次编译失败的时候,会在当前的环境中查找能让代码编译通过的方法,用于将类型进行转换,实现二次编译。
百思不得小赵
2022/12/01
5970
大数据技术之_16_Scala学习_06_面向对象编程-高级+隐式转换和隐式值
  设计一个 var total Int 表示总人数,我们在创建一个小孩时,就把 total 加1,并且 total 是所有对象共享的就 ok 了。我们使用伴生对象来解决。 示例代码如下:
黑泽君
2019/04/01
1.4K0
大数据技术之_16_Scala学习_06_面向对象编程-高级+隐式转换和隐式值
spark隐式转换 toDf_隐式转换是什么
解决方案就是自己定义一个隐式转换函数,double2int。这个隐士函数的功能也需要是唯一的
全栈程序员站长
2022/11/10
1.1K0
spark隐式转换 toDf_隐式转换是什么
scala 隐式详解(implicit关键字)
掌握implicit的用法是阅读Spark源码的基础,也是学习Scala其它的开源框架的关键,implicit 可分为: 隐式参数 隐式转换类型 隐式调用函数 1.隐式参数 当我们在定义方法时,可以把最后一个参数列表标记为implicit,表示该组参数是隐式参数。一个方法只会有一个隐式参数列表,置于方法的最后一个参数列表。如果方法有多个隐式参数,只需一个implicit修饰即可。 当调用包含隐式参数的方法是,如果当前上下文中有合适的隐式值,则编译器会自动为改组参数填充合适的值。如果没有编译器会抛出异
Albert陈凯
2018/04/04
1.4K0
推荐阅读
相关推荐
2021年大数据常用语言Scala(三十七):scala高级用法 高阶函数用法
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文