同样的功能,Scala的写出来的代码比java要精简很多。 我希望我的文章也尽可能的短,因为我知道程序员的时间是宝贵的。

Scala的安装

你可以去Scala官网去参考安装流程。首先你需要有Java 8 JDK, 然后你需要决定使用IntelliJ 或者 Eclipse作为你的IDE。 IntelliJ 对Scala比较友好,推荐使用,IntelliJ 里快捷键可以设置Eclipse模式,如果你是一个Eclipse开发者,这将让你舒服一些。

我想你已经配置好了Scala的命令行解释器。你可以通过在命令行里输入scala进入

定义一个常量

scala> val v1 = 11
v1: Int = 11

scala是静态类型的,但是在定义常量/变量的时候它不需要你指定类型,它会自动推断。如果你非要指定,它也不拦你。

scala> val v1:Int = 11
v1: Int = 11

注意:可能 scala 的作者为了故意显示和 java 的不同,在定义变量类型的时候,类型名在变量名的后边。

通过val定义的常量不能再次被赋值。

定义一个变量

scala> var v2 = "123"
v2: String = 123
scala> v2 = "234"
v2: String = 234

通过 var 关键字来定义变量,你可以看到通过 var 定义的变量可以再次被赋值。

lazy常量

通过lazy常量的定义,你可以将有可能不必要的复杂运算延迟到需要的时候再计算。而且lazy常量是可以传递的。

scala> lazy val a = {println("a");4+3}
a: Int = <lazy> //并未计算 4+3
scala> lazy val c = {println("c");a+3}
c: Int = <lazy> //lazy变量传递,虽然c的定义里用到了a,但是因为c也是lazy的,所以a也并未被计算
scala> c+3 //这时必须计算了
c  //c被计算
a  //a被计算
res39: Int = 13

定义一个方法

scala> def add(x:Int,y:Int):Int={
return x+y;
}
add: (x: Int, y: Int)Int

我们用完整的语法定义了一个方法,def 是定义方法的关键字,接着 add 是方法名。( )内是参数列表,同样是参数名在前,: 后边是参数类型。( )后边的 : Int 是方法返回值。 { }里边是方法体。注意 在方法返回值和方法体之间有个=

这个方法定义可以被这样简化定义

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

大部分情况下 Scala 可以帮我们推断返回类型,所以函数返回类型定义可以省略。当方法体只有一个语句的时候,{ }可以省略。 函数的return 关键字可以省略。如果你的方法体是个用{ }括起来的语法块,在没有return的情况下,就是{ }内的最后一个表达式的值。

在 scala 里如果你定义的方法没有明显指定返回值,那么这个方法的返回类型就是Unit,类似于 java 里 void 的类型。比如这样:

scala> def add(x:Int,y:Int){x+y}
add: (x: Int, y: Int)Unit

这个方法的返回值被scala识别为Unit,因为在定义时方法体{ }前边没有=

scala> def add(x:Int,y:Int)={x+y;println(x+y)}
add: (x: Int, y: Int)Unit

这个方法返回值被识别是Unit,是因为方法体内没有 return 关键字,而最后一个表达式

println(x+y)

的返回值是Unit的。

 

函数还是方法?

注意 前边我写的是定义一个方法method,而不是一个函数function。

我们说的Scala是一个结合了面向对象和函数式编程的语言。那么我们就看看函数是什么,它是怎么定义的。

scala> val func1 = (a:Int,b:Int)=>a+b
func1: (Int, Int) => Int =

scala> val func2=func1
func2: (Int, Int) => Int =

需要的注意的是=>这个符号。可以看到Scala编译器提示的 (Int, Int) => Int = ,后边的function2。 说明func1这个对象是Function2这个trait(你可以先理解成接口)的一个实现。Function2说明这个function有两个输入参数。Scala限制最多可以有22个参数,也就是到Function22.

 

函数是一个对象,我们可以调用它的toString方法

scala> func2.toString()
res10: String =

有一个小技巧那就是Scala的编译器有有自动补全功能,你可以敲入一部分代码,然后按tab键。比如我输入func2. ,然后按tab键

scala> func2.
apply   curried   toString   tupled

我们可以通过它的apply方法来调用我们定义的函数体。

scala> func2.apply(1,2)
res9: Int = 3

在Scala里apply方法是一个对象的默认方法。可以省去方法名直接用参数列表调用。

scala> func2(1,2)
res11: Int = 3

通过这种省略apply方法的调用方式,函数看起来和方法一样。

在Scala里方法和函数是不同的。我觉得大家只要注意一下几点就可以。

  1. Method 是一个有签名,有返回值,有方法体的代码段。 和我们在Java里定义的类的方法一样。当然你不能把一个代码块赋值给一个变量。
  2. Function 是一个对象,它有自己的方法,比如toString,apply 等。你当然可以把一个Function赋值给一个变量。你也可以方便的传递它。其他类型变量可以干的事情,Function 变量也可以干。这就是所谓的函数是第一等公民 (First Class Citizen).
  3. 一个Method可以转化为一个Function。Scala有时候在后台会帮我们做一些转化,这可能是好事,但是增加了大家对方法和函数的混淆。

我们再来看看方法,

scala> def methodAdd(a:Int,b:Int)=a+b
methodAdd: (a: Int, b: Int)Int

scala> val m1=methodAdd
:12: error: missing argument list for method methodAdd

我们不能直接将一个方法赋值给一个变量。但是我们可以通过给方法后边加一个” _”来将方法转化为函数。

scala> val m1=methodAdd _
m1: (Int, Int) => Int =

可以看到m1 是一个函数,它是通过methodAdd这个方法生成的。

既然函数是一个对象,我们可以传递它,那一个方法可以做参数吗?答案是肯定的。这对于一个纯的Java程序员来说,可能有点难以理解。我们看一下这个例子:

scala> def callAdder(adder:(Int)=>Int,a:Int)=adder(a)
callAdder: (adder: Int => Int, a: Int)Int

callAdder这个方法有两个参数,第一个参数是adder,它是一个输入Int,输出Int的函数,第二个参数是a,callAdder这个方法做的事情就是用传入的参数a,调用adder函数,返回结果。这种将操作传入的方式非常方便。在Java里要达到如此的效果,会非常笨重。我们把参数或者返回值中含有函数的函数称为高阶函数,这是函数式语言的一个重要特征。

然后我们定义一个方法:

scala> def addOne(a:Int)=a+1
addOne: (a: Int)Int

scala> val fAddOne=addOne _
fAddOne: Int => Int =

我们定义了一个addOne的方法,并用这个方法生成了一个function: fAddOne。现在如果我们要调用我们之前创建的callAdder 方法,我们该传递方法addOne还是函数fAddOne呢?

scala> callAdder(addOne,1)
res15: Int = 2

scala> callAdder(fAddOne,1)
res16: Int = 2

答案是都可以。你可能认为这里需要的是函数,传入方法会出错。但是Scala会在后台帮我们将方法转为函数。除了在这里,我们以后不再特别区分函数和方法。

 

1 对 “Rethink Scala 之二:变量和函数的定义”的想法;

  1. Java程序员的角度看,Scala中的method是Java里的方法,Scala中的function是将方法封装在apply中的函数对象。

发表评论

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

%d 博主赞过: