基本类型

Scala里支持的基本数据类型有Byte,Short,Int,Long,Char,String,Float,Double,Boolean。Scala 是完全面向对象的,这些基本类型都是类。除了这一点,你可以像你在Java里使用这些类型一样的用它。你可以写这样的代码:

scala> val a =3
a: Int = 3

scala> a.toString()
res9: String = 3

scala> 3.toString
res10: String = 3

注意 a.toString() 因为没有参数,所以()可以省略。 你可以写成a.toString。但是我们一般的做法是,如果这个方法有副作用,我们就加上(),如果没有副作用就可以根据你的喜好来省略.

因为这些基本类型也是对象,那么对于 1+2 这个表达式,1和2都是Int类的一个对象。所以1+2其实是1.+(2)的简写形式。1是Int类的对象,方法名是+,2是参数。并且这种简化形式并不是特殊的,而是对于所有的类和对象都适用。规则是:如果一个对象的方法只接受一个参数,你可以写作 object.method(arg) 也可以写作 object method arg。比如你可以在你的Scala 命令行解释执行器里执行 Console println 123 这和 Console.println(123)是一样的。

相等比较

对于Java程序员,肯定犯过这样的错误,判断两个字符串是否相等,用了==,而不是equals。在java里对于基本类型==判断的是值,而对于引用类型,==判断的是两个对象是否指向同一个对象。而要判断两个对象的值是否相同,你需要重载Object类的equals方法。这确实有点初学者有点难以捉摸。但是Scala里基本类型也是对象,所以==直接调用的就是equals,所以你每次都可以放心的使用==,但是记得对于自己定义的类重写equals和hashcode方法。

集合类型

Array

定义一个Array:

val numbers= new Array[Int](3)
numbers(0)=0
numbers(1)=1
numbers(2)=2

注意,Array是一个模板类,我们用Array[Int]来指定类型为Int的数组,后边的(3)是初始化数组为3个元素。如果访问数组第一个元素,我们用的是numbers(0), 在java里,你用的是方括号,而不是小括号 在Scala里,用圆括号,其实是在保持一致性。对象的功能只能通过方法来调用,numbers(0) 是numbers.apply(0) 的简写。如果你愿意,你也可以这么写numbers apply 0 正如我之前说的,这也是为了和你习惯的操作符调用方式的一致性。

numbers(0)=1 怎么理解呢?首先numbers是常量。但是我们可以改变numbers里的值。Array好比是营盘,里边的值好比是兵。俗话说铁打的营盘流水的兵。营盘没有变,里边的兵可以换。另外我们说了一个对象的功能只能通过方法来调用,那么numbers(0)=1 其实是numbers.update(0,1)的简写形式。这个也不是Array的特例。你自己的类里也可以用这个功能。如果你的一个类里定义了update方法它接收两个参数arg1,arg2。 你可以通过下边两种方式来调用你的update方法:

myObject.update(arg1,arg2)
myObject(arg1)=arg2

还有一点Scala里如果你的多个语句不是写在同一行,行尾的分号是可以省略的。

你也可以用下边的方式来初始化一个Array

val numbers=Array(0,1,2)

为什么没有new 关键字?这个Array,其实是类Array的伴生对象。然后调用这个伴生对象的apply方法生成一个Array的实例。后边我们会讲到类和伴生对象。

List

之前Array里的元素是可变的。但是List里的元素是不可变的。

val numbers = List(1,2,3)

这里你不能通过new 来生成一个List对象,因为List 的class 是abstract的。而上边语句实际调用的是List的伴生对象的apply方法。伴生对象你可以理解成这个类的一个singleton的对象。后边我们会讲到。

List的操作

合并两个list

val list1=List(1,2)
val list2=List(3,4)
val list3=list1.:::(list2)

你看到了一个你平常不会用的方法名:::,它就是合并两个list的方法。根据我们之前将的规则,它可以被简写成 list1:::list2。通过这个操作后,list3是一个全新的list。它包含元素,1,2,3,4 而list1,list2里边的元素并没有改变。

添加一个元素

0::list1

这里有点奇怪,增加元素是对list1的操作,::是方法名,不应该是list::0才对吗?

是的,你可以这样调用list1.::(0) ,但是简写的时候需要写成0::list1。

注意这是一个特列,需要记住,当方法名以冒号结尾,在简写时,需要调换参数和对象的位置。而且你发现0是增加在list的最前边。因为在列表最前边增加一个元素最快。如果你对顺序敏感,可以这样增加,最后得到的list,通过reverse来倒置。

空的list

Nil是空的list,你可以这样用它

1::2::Nil

是时候让你感受一下函数式编程的威力了

我们看一下这样一个场景,你有一个Int类型的list,里边存着大家的体重,你需要把体重大于100的挑出来,然后用冒号分隔打印出来。

val list=List(90,120,110,80,30)
list.filter((w:Int)=>w>100).mkString(":")

你会得到结果“120:110” filter会接受一个函数,根据你的函数来过滤元素,并返回另一个list。最棒的是你不用控制循环了。更加关注于逻辑的实现。其实上边的代码可以更简洁:

list.filter(w=>w>100).mkString(":")

类型信息不是必须的。因为这时list的filter方法需要传入函数的参数类型是确定的。不需要你再次指明。其实这个代码还是可以简写的:

list.filter(_>100).mkString(":")

因为参数名可以用下划线来匹配。这个匹配规则你需要了解一下,假如这里传入的函数只有一个参数,那么你可以用下划线来匹配。那如果你的函数有多个参数呢?你也可以用下划线来依次匹配多个参数,第一次出现下划线代表第一个参数,第二次出现下划线代表第二个参数。依次类推。这很方便,但是局限就是每个参数在你的表达式里只能用一次。

比如你定义了这样一个方法,它需要传入一个函数:

def add(op:(Int,Int)=>Int,od1:Int,od2:Int)=op(od1,od2)

你可以这样调用

add(_+_,1,2)

这些简化规则让你的程序更短,但是开始学的时候你需要花些时间来适应。

Tuple

元组Tuple是java里没有的数据类型,tuple就是一组元素,每个元素的类型值可以不同。Scala里的实现是最多有22个元素。就像函数最多有个22个方法一样。看来Scala语言的定义者对22很钟情。

定义一个tuple:

scala> val tuple=(1,2.3,true,"test")
tuple: (Int, Double, Boolean, String) = (1,2.3,true,test)

访问一个tuple:

scala> tuple._1
res19: Int = 1

注意tuple的访问是通过”._”+index来访问的。而且index是从1开始。因为元素里的每个元素类型可能不一样,所以不能像list一样提供list(index)来返回。

想想你在java里一个方法想要返回多个变量。你必须定义一个类。但是Scala里用元组就可以解决。元组里的值可以通过下边的办法快速赋值给多个变量

scala> val (a,b,c,d)=tuple
a: Int = 1
b: Double = 2.3
c: Boolean = true
d: String = test

Set

在Scala里Set有可变的mutable和不可变的immutable版本。如果不加包名,默认引用的是immutable的。

我们先来看immutable版的。

scala> val set = Set(1,2,3)
set: scala.collection.immutable.Set[Int] = Set(1, 2, 3)

scala> set+4
res5: scala.collection.immutable.Set[Int] = Set(1, 2, 3, 4)

scala> set
res6: scala.collection.immutable.Set[Int] = Set(1, 2, 3)

接着我们来看mutable版的

scala> val set = scala.collection.mutable.Set(1,2,3)
set: scala.collection.mutable.Set[Int] = Set(1, 2, 3)

scala> set+=4
res12: set.type = Set(1, 2, 3, 4)

scala> set
res13: scala.collection.mutable.Set[Int] = Set(1, 2, 3, 4)

注意是用+=来改变set的元素的。我们可以看到imutable版本的set每次操作都返回一个新的Set。

Map

同样的Map也有可变和不可变的版本。

Java里Map里存的是key和value。Scala的Map里存的多个包含两个元素的Tuple。我们可以用(1,”a”)这样的方法表示一个Tuple,也可以用1->”a”来生成一个Tuple

scala> val map = Map((1,"a"),2->"b")
map: scala.collection.immutable.Map[Int,String] = Map(1 -> a, 2 -> b)

我们接着来看一下对map的常用操作

scala> map+(3->"c")
res17: scala.collection.immutable.Map[Int,String] = Map(1 -> a, 2 -> b, 3 -> c)

scala> map.drop(1)
res18: scala.collection.immutable.Map[Int,String] = Map(2 -> b)

scala> map(2)
res19: String = b

scala> map.map(e=>(e._1+1,e._2+"b"))
res20: scala.collection.immutable.Map[Int,String] = Map(2 -> ab, 3 -> bb)

对map的删除操作,也可以写作map-2。最后一个操作是我们通过Map的map方法对map里的所有Tuple,第一个Int型元素加上1,第二个String型元素加上”b”
Scala对集合类型的操作非常丰富,我会在下一节的循环控制里继续讲解。

发表评论

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

%d 博主赞过: