scala成长之路(1)基本语法和数据类型
scala作为JVM上的Lisp,是一种geek类型的编程语言,也一直是我等java程序员眼中的梦寐以求的一门技能,遂下定决心花一段时间好好学习scala。第一天学习,主要介绍与java在编程上的主要区别。
首先,scala默认导入了java.lang包下的所有类,因此在scala中可以直接使用所有该包下的所有类,例如System、String
1. scala与java不同的一点是:scala是完全面向对象的,它没有基本数据类型,所有的变量、字面量或常量都是对象,所以你可以看到这种调用方式
scala> 1.toString()
res3: String = 1
因此,scala的数据类型基本都与java的基本数据类型包装类相对应:
数据类型 | 描述 |
---|---|
Byte | 8位有符号补码整数。数值区间为 -128 到 127 |
Short | 16位有符号补码整数。数值区间为 -32768 到 32767 |
Int | 32位有符号补码整数。数值区间为 -2147483648 到 2147483647 |
Long | 64位有符号补码整数。数值区间为 -9223372036854775808 到 9223372036854775807 |
Float | 32 位, IEEE 754标准的单精度浮点数 |
Double | 32 位 IEEE 754标准的单精度浮点数 |
Char | 16位无符号Unicode字符, 区间值为 U+0000 到 U+FFFF |
String | 字符序列 |
Boolean | true或false |
Unit | 表示无值,和其他语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。 |
Null | null 或空引用 |
Nothing | Nothing类型在Scala的类层级的最低端;它是任何其他类型的子类型。 |
Any | Any是所有其他类的超类 |
AnyRef | AnyRef类是Scala里所有引用类(reference class)的基类 |
注意其中的Unit类型,它和null不一样,null只能用于引用类型,不能用于数据类型:
scala> var a : Int = null
<console>:11: error: an expression of type Null is ineligible for implicit conversion
var a : Int = null
而Unit类型更多的是用于返回值表示没有返回值,也即返回值为空。scala中每个表达式都有返回值,但与c语言不同的是,scala中赋值表达式的返回值为空;而且scala中每个代码块都有返回值,即为代码块最后一行的返回值:
scala> var a = {println("hello world");var b = "aaa";b += "ccc"}
hello world
a: Unit = ()
2. 与其他函数式编程语言一样,函数在scala里也被视为“一等公民”,即函数可赋值,可作为参数进行传递,可作为返回值:
3. scala的for循环与java有所不同,它类似于python,只能用于遍历某个集合(但python还是可以通过enumerate来获得当前元素的位置信息,而scala则无此功能):
scala> for(i<-1 to 10)
| print(i + ",")
1,2,3,4,5,6,7,8,9,10,
同时,for循环的嵌套可以写在用一个for中,不同的层次之间用分号;链接:
for(i <- 1 to 9;j <- 1 to 3){
printf("%d,%d\n",i,j)
}
4. Array, List, Set, Map
首先需要明确,scala中的这四种容器类与java都是完全不同的,scala中除Tuple之外,所有容器都有类型指定
(1)Array是定长可变容器,类似于java中的list的定长版本,而且Array还需指定元素类型类似于java的泛型,注意使用的是中括号[]:
scala> var a = new Array[String](3)
a: Array[String] = Array(null, null, null)
如果使用显示初始化,则不需要new,类型自动推断:
scala> var a = Array(1,"12")
a: Array[Any] = Array(1, 12)
需要指出的是,在scala中,直接调用任何类的(),都等价于其apply方法,所以前边的程序也可以写作:var b = Array.apply(1,2,3)。而Array的索引下标则从0开始,可以修改任意元素的值:a(1) = 32,其等价于a.update(1,32)。此外,Array虽然是定长的,但是可以拼接其他可迭代容器,使用++生成一个新的Array:
scala> a ++ b
res10: Array[Int] = Array(1, 2, 3, 4)
(2)List是定长的不可修改容器,因此只能使用显式初始化:var a = List(1,3,4)。同时,List也提供类似的添加和拼接功能,分别利用:::和::进行List间的拼接以及添加元素:
var a = List(1,2,3)
var b = List(4,5,6)
a:::b
7::a
res17: List[Int] = List(7, 1, 2, 3)
需要注意的是,:::以及::都是右结合操作符,即将7添加到a应该是7::a而不是a::7,是右边的元素为操作方,左边为参数,同理,有一种创建List的方法:
scala> 1::2::3::Nil
res22: List[Int] = List(1, 2, 3)
其中Nil为默认导入的单例,其为一个空List
list的元素是不可变的,试图向其中的元素赋值会报错
scala> a(1) = 3
<console>:13: error: value update is not a member of List[Any] (从这里也可以看出等号左边的括号()解释器实际将其解释为update方法)
a(1) = 3
注意,List和Array都有个特点:一旦确定容器的类型,那么从容其中取出的元素也会默认为该类型,例如上边的 a由于在创建时指定了两种类型,则将List定位他们的公共父类:Any
scala> a(1)
res25: Any = aaa
(3)Tuple比较简单,它也许不能称为一种容器,它也是元素不可变的,但是它没有指定类型,即它可以同时容纳多种类型,取出时仍然是自身的类型:
scala> var b = (1,true,"a",2.2)
b: (Int, Boolean, String, Double) = (1,true,a,2.2)
Tuple有长度限制,最长为22,取出时也很特殊:b._1, b._2,下标从1开始
(4)Set和Map
Set和Map都有两种不同的实现:Mutable (可变)和 Immutable (不可变)
需要指出的是,默认直接使用的Set和Map都是不可变的,即默认导入的是scala.collection.immutable.Map和scala.collection.mutable.Set。
Set就是一个集合,主要用于迭代,要求其中的元素不能有重复。
Map 的基本用法如下( Map 类似于其它语言中的关联数组如 PHP )
val romanNumeral = Map ( 1 -> "I" , 2 -> "II",
3 -> "III", 4 -> "IV", 5 -> "V")
println (romanNumeral(4))