Scala基础学习
在篇主要内容:如何把Scala当做工业级的便携计算器使用,如何用Scala处理数字以及其他算术操作。在这个过程中,我们将介绍一系列重要的Scala概念和惯用法。同时你还将学到作为初学者如何浏览Scaladoc文档
1. 使用Scala解释器
2. 用var和val定义变量
3. 数值类型
4. 使用操作符和函数
5. 浏览Scaladoc
Scala解释器
启动Scala解释器的步骤如下:
安装Scala
确保scala/bin目录位于系统PATH中
在你的操作系统中打开命令行窗口,键入scala并按Enter键
现在键人命令,然后按Enter键。每一次,解释器都会显示出结果。例如,当你键人"8*5+2"(如下面加粗的文字),将得到42:
答案被命名为 res0 ,你可以在后续操作中使用这个名称:
正如你所看到的,解释器同时还会显示 结果的类型 ,拿本例来说就是Int、Double和java.lang.String
还可以调用方法,根据启动解释器的方式的不同,你可能可以使用Tab键补全而不用完整地手工键人方法名。你可以试着键人res2.to,然后按Tab键,如果解释器给出了如下选项:
说明Tab键补全功能是好的。接下来键入U并再次按Tab键,你应该就能定位到单条补全如下:
同样地,可以试试按T和J方向键。在大多数实现当中,你将看到之前提交过的命令,并且可以进行编辑。用方向键和Del键将上一条命令修改为:
正如你所看到的,Scala解释器读到一个表达式,对它进行求值,将它打印出来,接着再继续读下一个表达式。这个过程被称做 读取 一 求值 一 打印 一 循环 ,即REPL。从技术上讲,scala程序并不是一个解释器。实际发生的是,你输入的内容被快速地 编译成字节 码,然后这段字节码交由Java虚拟机执行。正因如此,大多数Scala程序员更倾向于将它称做"REPL"。
声明值和变量
除了直接使用res0、res1等这些名称之外,你也可以用 val 定义自己的名称:
以val定义的值实际上是一个 常量 ,你无法改变它的内容:
如果要声明其值可变的变量,可以用 var 定义其值可变的 变量 :
需要注意的是,不需要给出 值 或者 变量 的类型 , 这个信息可以从你用来初始化它的表达式推断出来。但还需注意一点,声明值或变量但不做初始化会报错。不过,在必要的时候,你也可以指定类型。例如:
由上图运行的结果可知,在Scala中,变量或函数的 类型 总是 写在变量或函数名称 的后面 。这使得我们更容易阅读那些复杂类型的声明。同时还需注意的是,在变量声明或赋值语句之后,我们并没有使用分号。在 Scala中,仅当 同一行代码中存在多条语句 时才需要用 分号隔开 。
常用类型
到目前为止你已经看到过Scala数据类型中的一些,比如Int和Double,和Java样Scala也有7种数值类型:Byte、Char、Short、Int、Long、Float和Double,以及1个Boolean类型。跟Java不同的是,这些类型是类。Scala并不刻意区分 基本类型 和 引用类型 。你可以对数字执行方法,例如:
scala> 1.toString
res6: String = 1
或者,更有意思的是,你可以:
scala> 1.to(10)
res7: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8,9, 10)
在Scala中,我们不需要 包装类型 。在 基本类型 和 包装类型 之间的转换是 Scala编译器 的工作。举例来说,如果你创建一个Int的数组,最终在虚拟机中得到的是一个int[]数组。
正如你在前面看到的那样,Scala用底层的 java.lang.String类 来表示 字符串 。不过,它通过 StringOps类 给字符串追加了上百种操作。举例来说,intersect方法输出两个字符串共通的一组字符:
scala> "Hello".intersect("World")
res8: String = lo
在这个表达式中java.lang. String对象 "Hello"被隐式地转换成了一个 StringOps对象 ,接着StringOps类的intersect方法被应用。因此,在使用Scala文档的时候,记得要看一下StringOps类。同样地,Scala还提供了 Richlnt 、 RichDouble 、 RichChar 等。它们分别提供了它们可怜的堂兄弟们 Int 、 Double 、 Char 等,所不具备的便捷方法。我们前面用到的to方法事实上就是Richlnt类中的方法。在表达式: 1.to (10) 中,Int值1首先被转换成Richlnt然后再应用to方法。
最后,还有 Biglnt 和 BigDecimal 类,用于任意大小(但有穷)的数字。这些类背后分别对应的是java.math. Biglnteger 和java.math. BigDecimal
注意:在Scala中,我们用方法,而不是强制类型转换,来做 数值类型之间的转换 。举例来说,99.44.tolnt得到99,99.toChar得到'c'。当然和Java一样, toString 将 任意的对象转换成字符串 。要将包含了数字的字符串转换成数值,使用tolnt或toDouble。例如,"99.44".toDouble得到99.44。
算术和操作符重载
Scala的算术操作符和你在Java或C++中预期的效果是一样的:
val answer=8*5+2
算术操作符:+ -*/%等操作符完成的是它们通常的工作,位操作符:&|^ >><<也一样。只有一点特别的,这些 操作符 实际上是 方法 。例如:
a+b
是如下方法调用的简写:
a.+(b)
这里的 + 是 方法名 。通常来说,你可以用:
a方法b
作为以下代码的简写:
a.方法(b)
这里的方法是一个带有两个参数的方法(一个隐式的和一个显式的)。例如
1.to (10)
可以写成:
1 to10
调用函数方法
除了方法之外,Scala还提供函数。相比Java,在Scala中使用数学函数更为简单,你不需要从某个类调用它的静态方法
scala> import scala.math._
import scala.math._
scala> sqrt(2)
res15: Double = 1.4142135623730951
scala> pow(2,4)
res16: Double = 16.0
scala> min(3,Pi)
res18: Double = 3.0
这些数学函数是在scala.math包中定义的。你可以用如下语句进行引入:
import scala.math._//在Scala中, _字符 是"通配符",类似Java中的 *字符
Scala没有静态方法,不过它有个类似的特性,叫做 单例对象 singleton object。通常,一个类对应有一个 伴生对象 companion object,其方法就跟Java中的静态方法一样
apply方法
在Scala中,我们通常都会使用类似 函数调用的 语法 。举例来说,如果 S是一个字符串,那么 S(i) 就是该字符串的第i个字符。在C++中,你会写:S[i];而在Java中,你会这样写:S.charAt(i)。在REPL中运行如下代码:
scala> "Hello"(4)
res19: Char = o
scala> "Hello"(0)
res20: Char = H
scala>
你可以把这种用法当做是 ()操作符 的 重载形式 ,它背后的实现原理是一个名为 apply的方法 。举例来说,在StringOps类的文档中,你会发现这样一个方法:
def apply(n: Int): Char
也就是说,"Hello"(4)是如下语句的简写:
"Hello".apply(4)
如果你去看Biglnt伴生对象的文档,就会看到让你将 字符串 或 数字 转换为 Biglnt对象 的apply方法。举例来说,如下调用
Biglnt ("1234567890")
是如下语句的简写:
Biglnt.apply("1234567890")
这个语句产出一个新的Biglnt对象,不需要使用new。例如:
Biglnt("1234567890") *Biglnt("112358111321")
像这样使用伴生对象的apply方法是Scala中构建对象的常用手法。例如,Array(l,4,9,16)返回一个数组,用的就是Array伴生对象的apply方法
Scaladoc
Java程序员们使用Javadoc来浏览Java AP,Scala也有它自己的版本,叫做Scaladoc。相比Javadoc,浏览Scaladoc更具挑战性。Scala类通常比Java类拥有多得多的便捷方
法。有些方法使用了你还没学到的特性。而且,有些特性展示出来的是它们的实现细节而并不是使用指南。我们可以在 www.scala-lang.org/api 在线浏览Scaladoc,不过也可以从 www.scala-lang.org/downloads#api 下载一个副本安装到本地。
和Javadoc按照字母顺序列出 类清单不同 ,Scaladoc的类清单按照 包排序 。如果你知道类名但不知道包名,可以用左上角的过滤器,参照下图:
点击×号可以清空过滤器。注意每个类名旁边的O和C,它们分别链接到对应的 类 (C)或 伴生对象 (O)。由于信息量大,Scaladoc可能读起来会比较累人。请记住以下这些小窍门:
■ 如果你想使用 数值类型 ,记得看看Richlnt、RichDouble等。同理,如果想使用字符串,记得看看SpringOps
■ 那些 数学函数 位于scala.math包中,而不是位于某个类中
■ 有时你会看到名称 比较奇怪的函数 。比如,Biglnt有一个方法叫做unary_-。这就是你定义前置的负操作符-x的方式
■ 标记为implicit的方法 对应的是自动(隐式)转换。比如,Biglnt对象拥有在需要时自动被调用的由int和long转换为Biglnt的方法
■ 方法可以 以函数作为参数 。例如,StringOps的count方法需要传人一个接受单个Char并返回true或false的函数,用于指定哪些字符应当被清点:
def count(p: (Char)=>Boolean) : Int
调用类似方法时,你通常可以一种非常紧凑的表示法给出函数定义。例如, s.count(_.isUpper) 的作用是清点所有大写字母的数量
如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
如果,您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是【Sunddenly】。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
■ 你时不时地会遇到类似 Range 或 Seq[Char] 这样的类。它们的含义和你的直觉告诉你的一样:一个是 数字区间 ,一个是 字符序列