Categories
语言基础

感受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_”,但在使用的时候不写前缀。

参考

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

5 replies on “感受scala函数式编程”

I am just writing to make you understand what a perfect experience my wife’s girl obtained using your webblog. She noticed so many pieces, which included what it is like to possess an excellent helping spirit to let others with no trouble learn about specific specialized things. You truly surpassed readers’ expected results. Thank you for providing these priceless, trusted, informative as well as fun tips about this topic to Lizeth.

I am also writing to make you know what a incredible encounter my friend’s girl gained reading through your web page. She learned such a lot of things, with the inclusion of what it is like to possess an incredible teaching style to make the others without hassle thoroughly grasp various tricky topics. You undoubtedly surpassed visitors’ expected results. Thanks for showing those valuable, trustworthy, revealing not to mention unique tips on your topic to Sandra.

I enjoy you because of all of your effort on this blog. Ellie enjoys doing internet research and it’s easy to see why. Most of us learn all of the lively method you offer precious suggestions through this web site and even increase participation from some other people on the matter so our favorite girl is now learning a lot of things. Take advantage of the rest of the year. You are always doing a really great job.

Leave a Reply

Your email address will not be published. Required fields are marked *