Scala基础

316 阅读5分钟

函数式编程思想

In computer science, functional programming is a programming paradigm where programs are constructed by applying and composing functions. It is a declarative programming paradigm in which function definitions are trees of expressions that each return a value, rather than a sequence of imperative statements which change the state of the program or world.
函数式编程(英语:functional programming)或称函数程序设计、泛函编程,是一种编程范式,它将电脑运算视为函数运算,并且避免使用程序状态以及易变对象。其中,λ演算(lambda calculus)为该语言最重要的基础。而且,λ演算的函数可以接受函数当作输入(引数)和输出(传出值)。

重要概念

  • 纯函数(pure function)
    • 或函数的纯粹性(purity),指没有副作用(side effect)的函数。副作用指的是状态的变化(mutation)。
  • 引用透明(referential transparency)
    • 对于相同的输入,总是得到相同的输出。如果f(x)的参数和函数体都是引用透明的,则f是纯函数。
  • 不变性(immutability)
    • 为了获得引用透明性,任何值都不能变化。
  • 函数是一等公民(first-class function)
    • 一切都是计算,函数式编程中只有表达式,变量和函数都是表达式
  • 高阶函数(higher order function)
  • 闭包(closure)
  • 表达式求值策略
    • 严格求值(call by value)
    • 非严格求值(call by name)
    • 惰性求值(lazy evaluation)
  • 递归函数(recursive function)
  • 尾递归(tail recursion)

优点

  • 生产效率高
  • 易于推理(reasoning)
  • 适合多核计算、云计算

Scala开发环境

需求

Java

1.8

scala

2.13.2

sbt

1.3.10

scala IDE

4.7

IDE

worksheet

相当于repo,可以直接在IDE中得到结果,交互式。

IDE编译

编写:project--package--scala app

编译运行:run configuration--scala application--已有/new configuration--main class:package_name.app_name--arguments--run

命令行编译

编写:scala app(.scala)

编译运行:cmd--scalac file_name.scala--

scala app中函数的名称要与文件名一致。

Scala的语言基础

变量

val:常量immutable variable

var:变量mutable variable

lazy val:惰性求值的常量

定义时,不需要显示指定变量类型,scala会自动进行类型推导。

类型体系

数值类型Numeric types

  • Byte 1字节
  • Short 2字节
  • Int 4字节
  • Long 8字节
  • Float
  • Double

低精度可以自由转换到高精度(从上往下),高精度转换到低精度会报错type mismatch,需要隐式转换。

布尔类型Boolean

字符类型Char

单引号

Unit

一般作为函数的返回值。()是unit的文字量。

Null

表示引用值为空,一般不用

Nothing

表示函数异常终止

字符串String

构建于Java的String之上,额外具有字符串插值(interpolation)的特性,类似于Shell语言。

函数与代码块Block

代码块Block

一般用于组织多个表达式,本身也是一个表达式。其最终结果是最后一个表达式的值。

分两种写法

{exp1;exp2;...}


{
exp1
exp2
...
}

函数function

def functionName(param:ParamType,...):ReturnType={
  //function body:exps
}

if与for

if表达式

注意if是表达式而不是语句。

if(exp)valA else valB

当没有else时,会返回Nothing。

for comprehension

用于表达循环的一种推导式。

try与match表达式

try表达式

try{}
catch{}
finally{}

类似于Java,try中抛出的异常会被catch所捕捉并抛出(_是通配符),finally中的表达式一定会被执行。

match表达式

exp match{ //主要用于pattern match中
  case p1 => val1
  case p2 => val2
  ...  
  case _ => valn
}

求值策略

  • Call By Value
    • 对函数实参求值,且仅求值一次
  • Call By Name
    • 函数实参每次在函数体内被用到时都会求值

通常使用CBV;如果函数形参类型以=>开头,则会使用CBN。

示例

场景1

CBV比CBN少执行一步

场景2

CBV比CBN多执行一步

场景3

由于x是CBV,loop传入之后就会进入死循环。而y是CBN,没有用到y的时候,就不会进入loop。

高阶函数

Scala中,函数是第一等公民,既像普通变量,又具有自己的类型。scala支持

  1. 把函数作为实参传递给另外一个函数
  2. 把函数作为返回值
  3. 把函数赋值给变量
  4. 把函数存储在数据结构里

函数与匿名函数

函数类型

A => B

表示把A映射为B

高阶函数

用函数作为形参或返回值的函数

匿名函数

即函数常量,也称为函数文字量(function literal)

(形参列表)=> {函数体}

柯里化Curried Function

把具有多个参数的函数转换为一条函数链,每个节点上是单一参数。

二者等价

可以通过柯里化定义一些通用函数。

递归与尾递归

递归函数recursive function

在函数式编程中,使用递归实现循环。

递归容易造成堆栈溢出,可以使用尾递归进行优化。

尾递归tail recursive function

所有递归形式的调用都出现在函数的末尾。当编译器检测到一个函数调用是尾递归时,它就覆盖当前的活动记录,而

不是在堆栈中去创建一个新的,因此不会造成堆栈溢出

示例****

Immutable Collection

collections-list即List[T]基础

//元素头部拼接list
::
//List拼接
:::
//返回首个
list.head
//返回除首个
list.tail
//返回是否空
list.isEmpty

list高级用法(搭配匿名函数)

//筛选true
list.filter
//转成list
string.toList
//取数直到false
list.takeWhile

list中的map

对list中的元素进行遍历然后映射,结合通配符"_"简化编写。使用flatMap将嵌套的list转为单层。

reduceLeft与flodLeft(规约操作)

reduceLeft

计算过程

代码

foldLeft

计算过程

相较于reduceLeft更通用,确保结果的数据类型为T。

代码

Rang与Stream

整数序列Range

Stream

即lazy list,惰性求值列表,在面对过大列表时,可以避免堆栈溢出。

tuple与map

元组tuple

用于封装函数的返回值

键值对map[k,v]

快速排序案例