Scala函数式编程

函数式编程简介

函数式编程(functional programming),Lisp作为最古老的函数式编程语言,已重获新生。新的函数式编程语言也层出不穷,比如Erlang,clojure,Scala等。

一个简单的Scala函数式编程例子如下:

List(1, 2, 3).foreach(x => println(x))

Scala函数式编程介绍

函数是一等公民

函数是第一等公民,指的是函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数,传入另一个函数,或者作为别的函数的返回值。

以下就是将一个匿名函数赋值给++变量的例子:

val ++ = (num: Int) => num + 1

++(2) // 3
++(6) // 7

// ++ 变量赋值给tmp变量
val tmp = ++
tmp(7) // 8
tmp(9) // 10

函数作为参数例子,一个最典型的例子就是一些connection的处理,connection处理完毕之后都需要close,可以使用函数作为参数,这样就不用每次都close数据了:

import scala.reflect.io.File
import java.util.Scanner

def scanFile(f: File, f: Scanner => Unit) = {
    val scanner = new Scanner(f.bufferedReader)
    try {
        f(scanner)
    } finally {
        scanner.close()
    }
}

scanFile(File("/tmp/test.txt"), scanner => println(scanner.next()))

一些常用的higher-order函数

higher-order函数指的是以函数做参数或者返回值是一个函数的函数。

List中的map,flatMap,foreach函数都是higher-order函数。

map例子,map函数的作用是使用一个函数调用集合中的各个元素,得到一个新的集合:

List(1, 2, 3).map({x => x * 2})  // List(2, 4, 6)

可以简化为:

List(1, 2, 3).map(x => x * 2)  // List(2, 4, 6)

还可以简化为:

List(1, 2, 3).map { x => x * 2 } // List(2, 4, 6)  currying函数的应用

还可以简化为:

List(1, 2, 3).map { _ * 2 } // List(2, 4, 6)

flatMap例子,flatMap函数的作用跟map函数类似,把多个集合合并成一个集合,注意,flatMap针对的是集合

List(1, 2, 3).flatMap { x => List(x * 2) } // List(2, 4, 6)

foreach例子:

List(1, 2, 3).foreach { println(_) }

函数和方法的区别

方法:方法指的是定义在类中的方法

class UseResource {
    def use(r: Resource): Boolean = { ... }
}

上面UseResource类中的use方法就是一个方法,it is a method.

函数:函数在scala中代表1个类型和一个对象,方法却不会,方法只会出现在类中。

val succ = (x: Int) => x + 1

scala允许将方法转换成函数,可以在方法后面添加 “_” 即可。比如:

val use_func: Resource => Boolean = new UserResource().use _

函数柯里化(function currying)

函数柯里化是一种把函数中多个参数改造成只有一个参数的技术。

def add(x: Int, y: Int) = x + y

add函数柯里化之后:

def add(x: Int) = (y: Int) => x + y

简化为:

def add(x: Int)(y: Int) = x + y

调用柯里化后的add函数:

add(2)(3) // 5
add(2) { 5 } // 7

scala支持把一个非柯里化的函数转换成一个柯里化函数,使用函数变量的curried方法:

def add(x: Int, y: Int) = x + y
val addVar = add _ // 转换成函数变量
val curryingFunc = addVar.curried // 使用curried方法转换成柯里化函数
curryingFunc(1) { 3 } // 4

// 或者定义add函数的时候直接使用函数变量
val add = (x: Int, y: Int) => x + y
val curryingFunc = addVar.curried
curryingFunc(1) { 3 } // 4

不过一般我们定义函数的时候都会定义成柯里化函数,而不会去转换:

def add(x: Int)(y: Int) = x + y
add(2) { 7 } // 9

// 实现一个map函数
def map[A, B](xs: List[A])(func: A => B) = xs.map { func(_) }
// List[String] = List(11, 21, 31)
map(List(1, 2, 3)) {
    x => x + "1"
}

鸭子类型

鸭子类型是动态类型的一种风格,使用鸭子类型就不可以不使用继承这种不够灵活的特性。

def withClose(closeAble: { def close(): Unit }, op: { def close(): Unit } => Unit) {
    try {
        op(closeAble)
    } finally {
        closeAble.close()
    }
}

class Connection {
    def close = println("close Connection")
}
val conn = new Connection()
withClose(conn, conn => println("do something with Connection"))
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
本文作者:Format
原文链接: http://fangjian0423.github.io/2015/06/12/scala-func-program/
版权归作者所有,转载请注明出处