变量定义

scala有两种变量,val 与 var,若是接触过js,肯定不会陌生
而相比于Java

  • val 类似于Java中的final 变量,一旦初始化,便不可再赋值
  • var则类似于Java中的非final变量,可以在生命周期中被多次赋值

比如

  1. val msg = "hello"
  2. var msg1 = "hello"

image.pngimage.png当重新为msg赋值时,就会报错
image.pngimage.pngimage.png,重新为msg1赋值时,则没有任何问题
此外,image.png可以看到,scala自动为msg定为String类型,这就是scala的类型推断能力
我们也可以手动指定变量的类型,不同于Java在变量名前声明,Scala在变量名后面加上冒号,后面跟上类型即可
image.png

函数定义

函数使用def关键字定义,接着是函数名,参数,以及返回类型,如

  1. // 函数名 参数及类型 返回类型
  2. def max(x: Int,y: Int): Int = {
  3. if (x > y){
  4. x
  5. }
  6. else y
  7. }

注意:虽然scala具有类型推断能力,但是在函数中,函数的参数必须指定类型

数据类型

Scala的数据类型与Java的数据类型基本一致,scala中所有的数据类型都是对象,没有java中的原生类型,如int,float等。也就是说,这些数据类型能够直接调用方法的,而在java中却需要包装类来调用。

Byte Int Short Long
Double Double Boolean String
Char
Unit 表示无值,与Java中的void相同,用于不返回任何结果的方法的结果类型,它仅有一个实例值,写为()
Null null或空引用
Nothing Nothing类型在Scala类层级的最底端,是任何其他类型的子类
Any 是所有其他类的超类
AnyRef 是Scala中所有引用类的基类

关于操作符

scala对操作符进行了大量的重载。而且scala允许特殊符号作为方法名
因此,在scala中,完全可以将操作符视为一个方法,函数,也可以在适当的时候,将方法视为操作符

  1. println( 1 + 2 )
  2. println( (1).+(2) )
  3. val oneToThree = List(1,2,3)
  4. println( oneToThree.indexOf(2))
  5. println( oneToThree indexOf 2 )
  6. //结果如下
  7. 3
  8. 3
  9. 1
  10. 1

在上面的code片段中,1 + 2+在这儿被理解为通常意义上的操作符,而在(1).+(2)中,是整数字面量1作为调用者,调用了名为+的方法,参数为2。
oneToThree.indexOf(2)中,很好理解,列表oneToThree调用了IndexOf方法,参数为2
而在 oneToThree indexOf 2 中,这样的表达仍然是有效的,indexOf同样可以被视为一个操作符,oneToThree作为左操作数,而2则作为右操作数。
对于大部分只有一个参数的方法,都可以写成这种形式
一个简单的规则:
如果方法使用操作符来标注,如a * b,那么左操作数是方法的调用者,可以改写为 a. * (b)。除非方法名以冒号结尾,这种情况下,方法被右操作数调用,如1 : : oneToThree::方法的调用者是oneToThree,参数是1,改写为方法的形式为oneToThree. :: (1)

关于函数副作用

scala中,如果看文档,查资料,会经常看到副作用这个词
副作用是函数式编程语言的一个说法,指的是破坏函数的“纯函数性”(或者说“无副作用性”)而言的。
首先解释一下什么叫纯函数,纯函数就是指给定相同输入就一定会有相同输出的函数。
从实现上来说这样的函数没有为自己保留生命周期超过自身调用的上下文,例如C语言里函数中的static变量的生命周期就会比函数调用要长。比如像sin(),cos()这样的函数就是纯函数的,给定相同的输入就一定会有相同的输出。
当然还有一类函数自身具有一定的状态,导致即便你给定相同的输入,也不一定会给出相同的输出。比如常见的随机函数rand()就是这一类。这一类函数内部保存的状态破坏了其函数的“纯度”,所以就被称为具有副作用。
纯函数和带有副作用的函数并非是不可转换的,只要将非纯函数的状态提取成一个context并在调用时传给函数,就能将函数改造为纯函数,比如同是随机函数的rand_r()就是个纯函数。
之所以提倡编写纯函数尽量避免副作用,是因为具有副作用的函数的状态其实类似于一个单例(无论多少次被调用,访问的都是同一个上下文),从而给函数的并发带来麻烦。除开并发上的缺点,带有副作用的函数也通常没有纯函数好调试。
直白的说,如果函数执行完成后,会修改函数外部变量的值,那么这个函数就是有副作用的。