分类
uncategorized

感受scala函数式编程

函数式编程是近来很热的概念,scala是一种典型的函数式编程语言,并且它与Java有很好的集成性。很多有名的开源产品都采用了scala,比如:kafka、tranquility、samza。因为工作需要调研以上产品,所以是时候学习scala了。

函数式编程是近来很热的概念,scala是一种典型的函数式编程语言,并且它与Java有很好的集成性。很多有名的开源产品都采用了scala,比如:kafka、tranquility、samza。因为工作需要调研以上产品,所以是时候学习scala了。

自己本身主语言是Java,并且没有了解过函数式语言。Java是一种命令式的编程语言,它与函数式语言在思维方式上有巨大的区别。scala与Java最大区别是函数特性。这篇文章不介绍scala语法特性细节,也不介绍函数式编程的概念,本文是自己在学习scala的时候对函数式编程这一特性的感受与理解。主要以代码的形式展现,相信代码是工程师之间交流最好的方式。

函数式与命令式

我们采用举例与对比的方式,例子中实现++的功能。首先一个命令式(Java)的例子:

int counter;
void inc(){
    counter++;
}

再看函数式的写法(scala):

def inc(counter: Int){
    counter + 1;
}

例子看起来很简单,但是它确实的反映了函数式编程几个重要的特性:

1. 强调不可变性
2. 强调不依赖外部数据
3. 面向表达式而不是语句

其中不可变性指的是,当需要改变变量的值的时候,不是直接改变而是采用==copy and change==的方式。不依赖外部数据指的是,函数所用的数据都通过参数传递进去,而不是使用公共数据。表达式与语句相对应,表达式都会返回值,所以面向表达式指的是函数都会有返回值。

函数式编程最初的设计用途是科学计算,它的特性都是为了==传入参数,函数加工,返回结果==而设计。同时这种设计也带来了一些优势。

  • 由于函数式编程中强调不可变性与不使用外部数据(公共数据),这样天然避免了并发时的同步问题
  • 函数组合与嵌套的特性,极大方便了对某些问题的描述
  • scala提供大量集合高阶函数,使得集合操作充满简便性与创造性

函数即对象

让我们一步一步解析scala中函数即对象的意思

apply方法

当类或对象有一个主要用途的时候,apply方法提供了一个很好的语法糖。

scala> class Foo (){ }
defined class Foo

scala> object foo{
     | def apply() = { println("I am Foo!") }
     | }
defined object foo

scala> foo()
I am Foo!

中我们通过“foo()”的方式调用了对象“foo”的apply方法。

进一步我们给apply方法添加参数。

scala> class Foo (){ }
defined class Foo

scala> object foo{
     | def apply(s: String) = { println(s) }
     | }
defined object foo

scala> foo("I am Foo!")
I am Foo!

Function

scala中预定义了22个Function,从Function1到Function22,每个Function中定义了函数apply,apply函数需要传入的参数个数分别从1到22。scala中的对象通过继承Function可以很方便的使用applay语法糖。

scala> object addOne extends Function1[Int, Int]{
     | override def apply(m: Int): Int = m + 1
     | }
defined object addOne

scala> addOne(2)
res2: Int = 3

函数即对象

请看下面的示例:

scala> val addOne = { (i: Int) => i+1 }
addOne: Int => Int = <function1>

scala> addOne(1)
res1: Int = 2

其中

val addOne = (i: Int) => i+1

是一个函数,它与上一小节中的形式是等价的,scala内部会把它转化成对象的形式并继承Function1。这样就可以使用了apply语法糖。scala正式借由Function与apply实现了函数即对象的语法特性。

面向表达式

scala是一个高度面向表达式的语言,表达式又是什么的呢?

简单表达式

var v1 = 1
val v2 = 1 + 1

使用函数的表达式

val v3 = addOne(1)

带有流程控制的表达式

var type: String = "T1"

val v4:Int = if (type == "T1") {
    1
} else if (type == "T2") {
    2
else {
    3
}

函数表达式形式

scala中函数表达式的形式可以是多种形态的

定义一个类”Counter”,并实现”add”方法

scala> class Counter(nu: Int) {
     | var num = nu;
     | def add(c: Counter): Counter = {
     | return new Counter(this.num + c.num);
     | }
     | }
defined class Counter

scala> val c1 = new Counter(1);
c1: Counter = Counter@29f0802c

scala> val c2 = new Counter(2);
c2: Counter = Counter@516ebdf8

scala> val c3 = c1.add(c2)
c3: Counter = Counter@36bc415e

scala> c3.num
res4: Int = 3

scala中可以使用空格替换表示从属关系的”.”,则”add”可以写成如下形式

scala> val c3 = c1 add c2
c3: Counter = Counter@36bc415e

scala> c3.num
res4: Int = 3

scala中允许方法以及变量名中包含特殊字符,将上例中的方法名改成”++”

scala> val c3 = c1 ++ c2
c3: Counter = Counter@36bc417e

scala> c3.num
res5: Int = 3

通过这两个特性,完成了表达式写法的渐变,并且一步一步接近通常意义的表达式形式

c1.add(c2)
c1 add c2
c1 ++ c2

操作符即函数

上一小节中我们看到可以使用特殊字符如”++”来命名方法与变量,为什么scala中会有这样的设定呢。其实在scala中没有传统意义的操作符,所有的操作符都是函数。

scala> val v = 1 + 1
v: Int = 2

上边表达式中的 “+” 与Java中的不一样,它其实是一个函数。scala是一个彻底的面向对象的语言,没有像Java中的基础数据类型,数字”1″会被装箱成”Int”对象,而”+”则是”Int”的方法,部分”Int”的符号方法如下:

def unary_~ : scala.Int
def unary_+ : scala.Int
def unary_- : scala.Int

scala规定单个符号作为方法名时,需要添加前对”unary_”,但在使用的时候不写前缀。

参考

版权声明:文章为作者辛勤劳动的成果,转载请注明作者与出处。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注