• Scala_函数式编程基础


    函数式编程基础

    函数定义和高阶函数

    函数字面量
    • 字面量包括整数字面量、浮点数字面量、布尔型字面量、字符字面 量、字符串字面量、符号字面量、函数字面量和元组字面量。

    scala> val i = 123
    i: Int = 123

    scala> val i = 3.14
    i: Double = 3.14

    scala> val i = true
    i: Boolean = true

    scala> val i = 'A'
    i: Char = A

    scala> val i = "Hello"
    i: String = Hello
    • 除了函数字面量我们会比较陌生以外,其他几种字面量都很容易理解。

    • 函数字面量可以体现函数式编程的核心理念

    • 在非函数式编程语言里,函数的定义包含了“函数类型”和“值”两种层 面的内容

    • 但是,在函数式编程中,函数是“头等公民”,可以像任何其他数据类型 一样被传递和操作,也就是说,函数的使用方式和其他数据类型的使用方 式完全一致

    • 这时,我们就可以像定义变量那样去定义一个函数,由此导致的结果是, 函数也会和其他变量一样,开始有“值”

    • 就像变量的“类型”和“值”是分开的两个概念一样,函数式编程中,函数的“类型”和“值”也成为两个分开的概念,函数的“值”,就是“函数字面量"

    • 下面我们一点点引导大家更好地理解函数的“类型”和“值”的概念。 我们现在定义一个大家比较熟悉的传统类型的函数,定义的语法和我们之前介绍 过的定义“类中的方法”类似(实际上,定义函数最常用的方法是作为某个对象的成员,这种函数被称为方法):

    函数的类型和值
    匿名函数、Lamda表达式与闭包
    • 我们不需要给每个函数命名,这时就可以使用匿名函数,如下:

    scala> (num: Int) => num*2
    res1: Int => Int = <function1>
    • 上面这种匿名函数的定义形式,我们经常称为“Lamda表达式”。“Lamda 表达式”的形式如下:

    (参数) => 表达式 //如果参数只有一个,参数的圆括号可以省略
    • 我们可以直接把匿名函数存放到变量中,下面是在Scala解释器中的执行过程:

    scala> val myNumFunc: Int => Int = (num: Int) => num*2 //这行是我们输入的命令,把匿名函数定义成一个值,赋值给myNumFunc变量
    myNumFunc: Int => Int = <function1> //这行是执行结果
    scala> println(myNumFunc(3)) //myNumFunc函数调用的时候,需要给出参数的值,这里传入3,得到乘法结果是6
    6
    • 实际上,Scala具有类型推断机制,可以自动推断变量类型,比如下面两条语句都是可以的:

    scala> val number: Int = 7
    number: Int = 7
    scala> val number = 7
    number: Int = 7
    • 所以,上面的定义中,我们可以myNumFunc的类型声明,也就是去掉 “Int=>Int”,在Scala解释器中的执行过程如下:

    scala> val myNumFunc = (num: Int) => num*2
    myNumFunc: Int => Int = <function1>
    scala>  println(myNumFunc(36))
    72
    • 下面我们尝试一下,省略num的类型声明,但是,给出myNumFunc的类型 声明,在Scala解释器中的执行过程如下:

    scala> val myNumFunc: Int => Int = (num) => num*2
    myNumFunc: Int => Int = <function1>
    • 不会报错,因为,给出了myNumFunc的类型为“Int=>Int”以后,解释器可 以推断出num类型为Int类型。

    • 闭包是一个函数,一种比较特殊的函数,它和普通的函数有很大区别

    • 普通函数:

    scala> var more = 1
    more: Int = 1
    scala> val addMore = (x: Int) => x > 0
    addMore: Int => Boolean = <function1>
    scala> addMore(10)
    res11: Boolean = true
    • 闭包:

    scala> var more = 1
    more: Int = 1
    scala> val addMore = (x: Int) => x + more
    addMore: Int => Int = <function1>
    scala> addMore(10)
    res5: Int = 11
    scala> more = 9
    more: Int = 9
    scala> addMore(10)
    res10: Int = 19
    • 每次addMore函数被调用时都会创建 一个新闭包

    • 每个闭包都会访问闭包创建时活跃的 more变量

    占位符语法
    • 为了让函数字面量更加简洁,我们可以使用下划线作为一个或多个参数的占 位符,只要每个参数在函数字面量内仅出现一次。

    scala> val numList = List(-3,-5,1,6,9)
    numList: List[Int] = List(-3, -5, 1, 6, 9)
    scala> numList.filter(x => x > 0)
    res0: List[Int] = List(1, 6, 9)
    scala>  numList.filter(_ > 0)
    res1: List[Int] = List(1, 6, 9)
    • 从上面运行结果可以看出,下面两个函数字面量是等价的。

    x => x > 0
    _ > 0
    
    • 有时你把下划线当作参数的占位符时,编译器有可能没有足够的信息推断缺 失的参数类型。例如,假设你只是写_ + _:

    scala> val f = _ + _
    <console>:7: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$plus(x$2))
          val f = _ + _
                  ^
    <console>:7: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.$plus(x$2))
          val f = _ + _
                      ^
    • 这种情况下,你可以运用 冒号指定类型,如下:

    scala> val f = (_: Int) + (_: Int)
    f: (Int, Int) => Int = <function2>
    scala> f(5,8)
    res2: Int = 13
    • 请留心 _ + _将扩展成带两个参数的函数字面量。这也是仅当每个参数在函数 字面量中最多出现一次的情况下你才能运用 这种短格式的原由 。多个下划线 指代多个参数,而不是单个参数的重复运用 。第一个下划线代表第一个参数, 第二个下划线代表第二个,第三个……,如此类推。

  • 相关阅读:
    动态更新活动条件
    使用本地服务异步执行自定义活动业务逻辑
    隐藏自定义复合活动的内部实现
    如何开发一个基本的复合活动
    HTML5性能之争 —— 单线程:缺点还是特点?
    CDNJS —— Web 上最快的 JavaScript 资源库
    Comfusion 4.1 发布,桌面 Linux 发行
    FreeBSD 9.1 正式版已经可以下载
    Squid Analyzer 5.0 发布,Squid日志统计
    MemSQL 1.8 发布,号称最快的关系数据库
  • 原文地址:https://www.cnblogs.com/zxbdboke/p/10466327.html
Copyright © 2020-2023  润新知