scala笔记整理:函数式编程(代码片段)

author author     2022-11-04     197

关键词:

[TOC]


作为值传递的函数

测试代码如下:

package cn.xpleaf.bigdata.p4.function

/**
  * scala中关于函数的操作
  */
object _01FunctionOps 
  def main(args: Array[String]): Unit = 
    functionOps1
  

  /**
    * 作为值传递的函数
    * 将一个函数作为值传递给另外一个函数变量的时候,约定需要在函数后面加上:空格和下划线
    * 相当于数据库中的别名,或者数据库表对应的视图
    */
  def functionOps1: Unit = 
    def sayHi(name:String) = println("Hello, " + name)

    def sayHello = sayHi _

    sayHello("xpleaf")
  

输出结果如下:

Hello, xpleaf

匿名函数

测试代码如下:

package cn.xpleaf.bigdata.p4.function

/**
  * scala中关于函数的操作
  */
object _01FunctionOps 
  def main(args: Array[String]): Unit = 
    functionOps2
  

  /**
    * 匿名函数,说白了就是没有函数名字
    *     匿名函数就和java中的匿名内部类一样,是只适合使用一次的函数
    *     一般如果一个函数的参数是一个函数,这种情况下多用匿名函数来作为参数进行传递
    */
  def functionOps2: Unit = 
    val printName = (name:String) => println("你好," + name)
    printName("xpleaf")
  

输出结果如下:

你好,xpleaf

其实前面在学习ArrayBuffer的时候已经有使用过匿名函数:

scala> val ab = ArrayBuffer[Int](3, 8, 2, 20, 5, 7)
ab: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(3, 8, 2, 20, 5, 7)
scala> ab.sortWith((v1, v2) => v1 > v2)
res209: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(20, 8, 7, 5, 3, 2)

带函数参数的函数(高阶函数)

说明的作用有两个(匿名函数作为参数和返回值为匿名函数),具体参考下面的测试代码:

package cn.xpleaf.bigdata.p4.function

/**
  * scala中关于函数的操作
  */
object _01FunctionOps 
  def main(args: Array[String]): Unit = 
//    functionOps1
//    functionOps2
    functionOps3
  

  /**
    * scala的高阶函数,就是函数的 [参数是函数] 的函数,把这种函数称为高阶函数
    */
  def functionOps3: Unit = 

    // 1.匿名函数作为参数
    def highOrderFunc(name:String, func:(String) => Unit): Unit = 
      func(name)
    

    highOrderFunc("xpleaf", (name:String) => println("Hello, " + name))

    // 2.将匿名函数作为返回值传递给另外一个函数
    def getGoodBayFunction(gMsg: String) = (gName: String) => println(gMsg + ", " + gName)

    val goodbayFunction = getGoodBayFunction("good bye")
    goodbayFunction("xpleaf")

  

输出结果如下:

Hello, xpleaf
good bye, xpleaf

参数(类型)推断

测试代码如下:

package cn.xpleaf.bigdata.p4.function

import scala.collection.mutable.ArrayBuffer

/**
  * scala中关于函数的操作
  */
object _01FunctionOps 
  def main(args: Array[String]): Unit = 
//    functionOps1
//    functionOps2
//    functionOps3
    functionOps4
  

  /**
    * 对于匿名函数的省略写法
    */
  def functionOps4: Unit = 
    val ab = ArrayBuffer[Int](1, 2, 3, 4, 5)

    // val newAB = ab.map((x:Int) => x * 100)
    // val newAB = ab.map((x) => x * 100)
    // val newAB = ab.map(x => x * 100)
    val newAB = ab.map(100 * _)
    println(newAB)  // ArrayBuffer(100, 200, 300, 400, 500)

  

输出结果如下:

ArrayBuffer(100, 200, 300, 400, 500)

常见高阶函数——map函数

遍历集合中的每一个元素,返回也是一个集合,集合大小和之前集合相等。
  • 快速产生0.1, 0.2, 0.3等方式的数字
scala> (1 to 9).map(0.1 * _).foreach(println(_))
0.1
0.2
0.30000000000000004
0.4
0.5
0.6000000000000001
0.7000000000000001
0.8
0.9
  • 打印三角形
scala> (1 to 9).map("*" * _).foreach(println(_))
*
**
***
****
*****
******
*******
********
*********

在这里,我们还用到了foreach,它和map很像,只不过它的函数并不返回任何值,foreach只是简单的将函数应用到每个元素而已。

常见高阶函数——filter函数

按照过滤条件,将原集合中不符合条件的数据过滤掉
  • 输出所有匹配某个特定条件的元素,得到一个序列中的所有偶数
scala> (1 to 9).filter(line => line % 2 == 0).foreach(println(_))
2
4
6
8

scala> (1 to 9).filter(_ % 2 ==0).foreach(println)
2
4
6
8

常见高阶函数——reduce函数

scala> (1 to 9).reduce((v1:Int, v2:Int) => v1 + v2)
res4: Int = 45
scala> (1 to 9).reduce(_ + _)
res6: Int = 45
scala> (1 to 9).reduceLeft(_ + _)
res7: Int = 45
scala> (1 to 9).reduceRight(_ + _)
res8: Int = 45

可以写下面一个函数来验证reduce函数的执行过程:

scala> val process = (v1:Int, v2:Int) => println(s"v1=$v1, v2=$v2")
process: (Int, Int) => Unit = <function2>
scala> def pro(v1:Int, v2:Int):Int = 
     |   println(s"v1=$v1, v2=$v2")
     |   v1 + v2
     | 
pro: (v1: Int, v2: Int)Int
  • reduce的执行流程
scala> (1 to 9).reduce((v1:Int, v2:Int) => pro(v1, v2))
v1=1, v2=2
v1=3, v2=3
v1=6, v2=4
v1=10, v2=5
v1=15, v2=6
v1=21, v2=7
v1=28, v2=8
v1=36, v2=9
res0: Int = 45
  • reductLeft的执行流程
scala> (1 to 9).reduceLeft((v1:Int, v2:Int) => pro(v1, v2))
v1=1, v2=2
v1=3, v2=3
v1=6, v2=4
v1=10, v2=5
v1=15, v2=6
v1=21, v2=7
v1=28, v2=8
v1=36, v2=9
res2: Int = 45
  • reductRight的执行流程
scala> (1 to 9).reduceRight((v1:Int, v2:Int) => pro(v1, v2))
v1=8, v2=9
v1=7, v2=17
v1=6, v2=24
v1=5, v2=30
v1=4, v2=35
v1=3, v2=39
v1=2, v2=42
v1=1, v2=44
res3: Int = 45

这样的话执行过程就非常清晰了,reduce和reduceLeft都是从左边的操作数开始,而reduceRight是从右边的操作数开始。

常见高阶函数——sortWith函数

scala> (1 to 9).sortWith((v1:Int, v2:Int) => v1 > v2).foreach(println(_))
9
8
7
6
5
4
3
2
1

scala> (1 to 9).sortWith(_ > _).foreach(println)
9
8
7
6
5
4
3
2
1

闭包

函数的变量不在其作用域内被调用,就是闭包的概念,看下面一个例子:

def closePackage: Unit =
    def mulBy(factor:Double) = (x:Double) => factor * x
    val triple = mulBy(3)
    val half = mulBy(0.5)
    println(triple(14) +" " + half(14)) //42, 7

1)mulBy的首次调用将参数变量factor设为3,。该变量在(x:Double)=&gt;factor *x函数的函数体内被引用。该函数被存入triple.然后参数变量factor从运行时的栈上被弹出。

2)mulBy再次被调用,这次factor被设为0.5.该变量在(x:Double)=&gt;factor *x函数的函数体内被引用,该函数被存入half.

每一个函数被称为闭包(closure)。闭包有代码和代码用到的任何非局部变量定义构成。

其实上面的mulBy函数就类似于下面这个:

def mulBy1(factor:Double, x:Double) = 
    factor * x

原本还希望进一步写成下面这样子的:

def mulBy2(factor:Double, x:Double) = 
    def work(x:Double) = 
        factor * x
    
    return work

但在scala中不支持这样的写法,下面这样写才可以:

def mulBy2(factor:Double) = 
    (x:Double) => factor * x

// 加个return也不行

之前在Python中使用过闭包,类似上面的例子,Python就可以这样写:

def mulBy(factor):
    def work(x):
        return factor * x
    return work

测试如下:

>>> def mulBy(factor):
...     def work(x):
...             return factor * x
...     return work
...
>>> triple = mulBy(3)
>>> half = mulBy(0.5)
>>> triple(14)
42
>>> half(14)
7.0

当然,只是Python的语法格式就没有scala那么灵活了。

柯里化(currying函数)

1、柯里化(currying)指的是将原来接受2个参数的函数变成新的接受一个参数的函数的过程。新的函数返回一个以原有第二个参数作为参数的函数。

2、在函数调用的过程中,就变为了两个函数连续调用的形式。在Spark源码中,也有体现,所以对()()这种形式的Curring函数,一定要掌握。

以下函数接受一个参数,生成另一个接受单个参数的函数,要计算两个数的乘积,调用如下:

/**
    * curryingFunction: 柯里化函数
    */
def curryingFunction =
    def totalSum(x:Int, y:Int) = println( x + y)

    //totalSum(4,5)

    def totalSumAtTime(x:Int) = (y:Int) => x + y
    println(totalSumAtTime(4)(5))

scala学习(函数式编程面向对象编程)(代码片段)

文章目录函数式编程基础函数编程函数定义函数参数函数至简原则高阶函数编程面向对象编程基础面向对象编程高阶面向对象编程函数式编程基础函数编程函数定义packagelearn03objectdemo01defmain(args:Array[String]):Unit=//无参、无返回... 查看详情

scala学习(函数式编程面向对象编程)(代码片段)

文章目录函数式编程基础函数编程函数定义函数参数函数至简原则高阶函数编程面向对象编程基础面向对象编程高阶面向对象编程函数式编程基础函数编程函数定义packagelearn03objectdemo01defmain(args:Array[String]):Unit=//无参、无返回... 查看详情

scala函数式编程(代码片段)

Scala函数式编程什么是函数式编程?1、函数式编程将计算视为数学上的函数计算2、函数成为了和普通的值一样的"头等公民",可以像任何其他数据类型的值一样被传递和操作函数式编程成为越来越流行的编程范式1... 查看详情

scala函数式编程函数式的数据结构下(代码片段)

前情提要Scala函数式编程指南(一)函数式思想介绍scala函数式编程(二)scala基础语法介绍Scala函数式编程(三)scala集合和函数Scala函数式编程(四)函数式的数据结构上1.List代码解析今天介绍的内容,主要是对上一篇介绍的sca... 查看详情

scala学习之函数式风格编程(代码片段)

...unctional-programming.htmlScala允许您以面向对象编程(OOP)风格、函数式编程(FP)风格甚至混合风格编写代码,结合使用这两种方法。本书假设您是从Java、C++或C#等OOP语言来到Scala的& 查看详情

scala函数式编程函数式的错误处理(代码片段)

前情提要Scala函数式编程指南(一)函数式思想介绍scala函数式编程(二)scala基础语法介绍Scala函数式编程(三)scala集合和函数Scala函数式编程(四)函数式的数据结构上Scala函数式编程(四)函数式的数据结构下1.面向对象的... 查看详情

scala学习笔记-函数式编程(14)

将函数赋值给变量1//Scala中的函数是一等公民,可以独立定义,独立存在,而且可以直接将函数作为值赋值给变量2//Scala的语法规定,将函数赋值给变量时,必须在函数后面加上空格和下划线34defsayHello(name:String){println("Hello,"+name)}... 查看详情

scala函数式编程初步(高阶函数)(代码片段)

参数式函数定义一个参数是函数的函数。(完整定义=>匿名函数)objecthelloWorlddefmain(args:Array[String]):Unit=defaddxy(x:Int,y:Int):Int=x+ydefmulxy(x:Int,y:Int):Int=x*ydeffunc1(a:Int,b:Int,f:(Int,Int)=> 查看详情

spark基础学习笔记08:scala简介与安装(代码片段)

文章目录零、本讲学习目标一、Scala简介(一)Scala概述(二)函数式编程(三)Scala特性1、一切都是对象2、一切都是函数3、一切都是表达式(四)在线运行Scala二、Windows上安装Scala(一)... 查看详情

scala笔记整理:actor和akka(代码片段)

[TOC]概述?Scala的Actor有点类似于Java中的多线程编程。但是不同的是,Scala的Actor提供的模型与多线程有所不同。Scala的Actor尽可能地避免锁和共享状态,从而避免多线程并发时出现资源争用的情况,进而提升多线程编程的性能。Spark... 查看详情

scala笔记整理:actor和akka(代码片段)

[TOC]概述?Scala的Actor有点类似于Java中的多线程编程。但是不同的是,Scala的Actor提供的模型与多线程有所不同。Scala的Actor尽可能地避免锁和共享状态,从而避免多线程并发时出现资源争用的情况,进而提升多线程编程的性能。Spark... 查看详情

scala学习函数式编程续case类(代码片段)

文章目录CASECLASSESWith`apply`youdon’tneed`new`NomutatormethodsAn`unapply`method`copy`method`equals`and`hashCode`methods`toString`methodsThebiggesta 查看详情

scala的函数式编程(代码片段)

Scala的函数式编程  Scala的函数式编程的特点  -高阶函数  -闭包  -模式匹配可参考:http://blog.51cto.com/14048416/2337136  -单一赋值  -延迟计算  -类型推导  -尾部调用优化 &e... 查看详情

《java8实战》读书笔记12:函数式编程(代码片段)

《Java8实战》读书笔记12:函数式编程第13章函数式的思考13.1实现和维护系统13.1.1共享的可变数据13.1.2声明式编程13.2什么是函数式编程13.2.1函数式Java编程13.2.2引用透明性13.2.3面向对象的编程和函数式编程的对比13.2.4函数式编... 查看详情

scala基础(代码片段)

...是一门类似Java的多范式语言,集合了面向对象编程和函数式编程的特性。使用Scala语言编写Spark应用程序的考虑:1)Scala具有强大的并发性,支持函数式编程,可以更好的支持分布式系统。在大数据时代,... 查看详情

scala编程之惰性函数(代码片段)

一、为什么需要惰性函数惰性计算(尽可能延迟表达式求值)是许多函数式编程语言的特性。惰性集合在需要时提供其元素,无需预先计算它们,这带来了一些好处。首先,您可以将耗时的计算推迟到绝对需要的时候。其次,您可以创造... 查看详情

spark基础学习笔记13:scala函数(代码片段)

文章目录零、本讲学习目标一、声明函数(一)显式声明函数1、声明格式2、注意事项3、案例演示(二)隐式声明函数1、声明格式2、注意事项3、案例演示二、Scala函数种类(一)成员方法1、基本概念2、... 查看详情

scalaidea安装配置入门helloworld(代码片段)

...门多范式的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。Scala是一门以java虚拟机(JVM)为目标运行环境并将面向对象和函数式编程的最佳特性结合在一起的静态类型编程语言。Scala是一门多范式(multi-paradi... 查看详情