翻译自:https://docs.scala-lang.org/overviews/scala-book/prelude-taste-of-scala.html
我们期望通过这本书让你认识到Scala是一门美妙、紧追时代且富有表达性的编程语言。在本文中我们将粗略地介绍Scala的主要特性。这篇文章之后我们将遵循循序渐进的原则让大家更深入地学习本文涉及的内容以及更多与Scala相关的内容。
我们假设大家具备某种语言基础。
概览
在学习Scala之前,这里先给出一些Scala的重要特性:
- 它是一门高级程序设计语言
- 它是静态类型语言
- 语法简练但是仍然非常具有可读性-我们称之为富有表达性
- 支持面向对象的编程范式
- 支持函数式编程
- 具有相当成熟的类型推断系统
- Scala代码最终也是被编译为*.class*文件使之能运行于java虚拟机
- 在Scala中可以使用Java类库
Hello,world
“Hello,world“似乎已经成为了开启很多语言的传统,本文也先给出”Hello,world"在Scala中的代码实例:
object Hello extends App {
println("Hello,world")
}
将这部分代码写入一个Hello.scala文件中,接着你可以通过 scalac 编译它(前提已经安装Scala):
scalac Hello.scala
如果你先前对java已经有所了解那么你将能更好地理解scalac,它就像javac,用scalac编译之后将产生两个文件,分别为:
- Hello$.class
- Hello.class
它们跟javac创建的字节码文件*.class*一样,它们运行于JVM之上,在Scala命令行输入:
scala Hello
它将在终端输出“Hello,world“
Scala交互式解释器(REPL)
Scala交互式解释器是一个用户在命令行解释器被用于在命令行测试代码。之后你们都可以通过它测试文中给出的代码实例。
在终端中输入scala打开一个交互式解释器的会话,你将看到如下输出:
你可以输入一些Scala表达式看看REPL如何工作:
Scala中的两种变量类型
Scala有两种类型的变量:
- val是一种不可变的变量-像java中final修饰的变量-推荐代码中尽量使用不可变变量
- var创建一个可变的变量,仅当有特定的原因时才使用这种类型的变量 实例
- 例子
val x = 1 //immutable(不可变)
var y = 0 //mutable(可变)
声明变量类型
在Scala中,你通常可以在创建变量时不声明它的类型:
val x = 1
val s = "a string"
val p = new Person("Regina")
Scala通常能推断出数据类型,如下图:
这种特性被称之为 类型推断,它能让你的代码更加精简。当然,你也可以显示的指定变量的类型:
val x : Int = 1
val s : String = "a string"
val p : Person = new Person("Regina")
控制语句
这里快速浏览一下Scala中的控制语句。
if/else
Scala中的if/else与其它语言中的类似:
if (test1) {
doA()
} else if (test2) {
doB()
} else {
doC()
}
然而,与java等其它语言不同的是,Scala的if/else语句返回一个值,你可以把它用作一种三元运算符:
val x = if (a < b) a else b
match 表达式
Scala中的 match 表达式, 与JAVA等语言中的switch类型:
val result = i match {
case 1 => "one"
case 2 => "two"
case _ => "not 1 or 2"
}
match 表达式不仅可以用于整型,它可被用于任意数据类型,包括布尔型:
val booleanAsString = bool match {
case true => "true"
case false => "false"
}
接下来给出一个 match 表达式作为方法体的例子,该例中match匹配来多种数据类型:
def getClassAsString(x : Any) : String = x match {
case s : String => s + " is a String"
case i : Int => "Int"
case f : Float => "Float"
case l : List[_] => "List"
case p : Person => "Person"
case _ => "Unknown"
}
强力的match表达式是Scala中的一个重要特性,后面章节还会进行详细介绍。
try/catch
Scala中的try/catch语句用于捕获异常。它跟java类似,但是它的语法是跟match保持一致的:
try {
writeToFile(text)
} catch {
case fnfe : FileNotFoundException => println(fnfe)
case ioe : IOException => println(ioe)
}
for循环
Scala中的for循环:
for (arg <- args) println(arg)
//"x to y(include)" syntax
for (i <- 0 to 5) println(i)
//"x to y by step" syntax
for (i <- 0 to 10 by 2) println(i)
你能通过给for循环加上yield关键字进而创建一个for表达式。这里给出一个将所有数乘以2的for表达式:
同时给出一个在List中获取字符串长度超过4的for表达式:
val fruits = List("apple","banana","lime","orange")
val fruitLengths = for {
f <- fruits
if f.lenght > 4
} yield f.length
while 和 do/while
Scala也有while和do / while循环,接下来展示语法样式:
//while loop
while (condition) {
statement(a)
statement(b)
}
//do-while
do {
statement(a)
statement(b)
} while (condition)
类
先上一个Scala类的例子:
class Person(var firstName : String, var lastName : String) {
def printFullName() = println(s"$firstName $lastName)
}
可像下面那样使用这个类
val p = new Person("Julia", "Kern")
println(p.firstName)
p.lastName = "Manes"
p.printFullName()
你应该已经注意到在Scala中不需要创建“get"和“set”方法就可以获取类中的对应字段。
接下来我们给出一个更复杂的例子:
class Pizza (
val crustSize : CrustSize,
val crustType : CrustType,
val toppings : ArrayBuffer[Topping]
) {
def addTopping(t : Topping) : Unit = toppings += t
def removeTopping(t : Topping) : Unit = toppings -= t
def removeAllToppings() : Unit = toppings.clear()
}
上述代码中的ArrayBuffer 可以理解为 java中的ArrayList。我们相信正在阅读本文的读者在没有给出CrustSize、CrustType、Topping类的具体实现的情况下也能读懂上述代码的运作机制。
Scala方法
与其它面向对象编程语言一样,Scala类也有方法,Scala方法的语法如下面的两个例子中所示:
def sum(a : Int, b : Int) : Int = a + b
def concatenate(s1 : String, s2 : String) : String = s1 + s2
与此同时,方法的返回值类型并非一定要给出,你也可以像下面那样写这两个方法:
def sum(a : Int, b : Int) = a + b
def concatenate(s1 : String, s2 : String) = s1 + s2
你可以像下面那样调用方法:
val x = sum(1,2)
val y = concatenate("foo", "bar")
我们这里只是简单的展示类一些Scala方法的使用,在Scala方法中你还可以给方法参数提供默认值等。
特质(Traits)
特质是Scala中一个非常重要的特性,它能让你的代码更加模块化。下面给出三个特质的例子:
trait Speaker {
def speak() : String //没有方法体,所以它是一个抽象方法
}
trait TailWagger {
def startTail() : Unit = println("tail is wagging")
def stopTail() : Unit = println("tail is stoppped")
}
trait Runner {
def startRunning() : Unit = println("I'm running")
def stopRunning() : Unit = println("Stopped running")
}
你可以构建一个 Dog 类实现所有特质并给出 speak 方法的具体行为:
class Dog(name : String) extends Speaker with TailWagger with Runner {
def speak() : String = "Woof!"
}
相似的,这里给出一个 Cat 类它覆盖了多个特质的方法:
class Cat extends Speaker with TailWagger with Runner {
def speak() : String = "Meow"
override def startRunning() : Unit = println("Yeah...I don't run")
override def stopRunning() : Unit = println("No need to stop")
}
即使对上面的特质不能很好地理解也不要慌,本书之后的章节还会详细论述。
集合类
如果你先前是学习Java的,你或许会在Scala中使用Java集合。但是我们还是强烈推荐你学习Scala集合类的基础–List、ListBuffer、Vector、ArrayBuffer、Map、Set。Scala集合类的一个好处就是它们提供了许多强有力的方法。
填充list
创建被填充了的简单list曾风靡一时,Scala中提供了许多填充list的方法,这里先展示一些:
val nums = List.range(0,10)
val nums = (1 to 10 by 2).toList
val letters = ('a' to 'f').toList
val letters = ('a' to 'f' by 2).toList
Sequence 方法
因为这里有很多顺序集合–Array、ArrayBuffer、Vector、List等,让我们看看我们可以怎样操作 List。在此之前我们先准备两个list:
val nums = (1 to 10).toList
val names = List("joel", "ed", "chris", "maurice)
foreach 方法使用:
names.foreach(println)
foreach 结合 filter 方法:
nums.filter(_ < 4).foreach(println)
在给出使用 map 方法的一些例子:
val doubles = nums.map(_ * 2)
val capNames = names.map(_.capitalize) //把首字母大写
val lessThanFive = nums.map(_ < 5)
map 方法对集合中的每个元素按你提供的算子进行处理并返回一个新的、被转换了的值。
下面给出一个更加强力的集合方法,这就是foldLeft:
第一个括号内的值是一个种子值,第一个函数以3为初始值加上nums集合的所有数据,第二个函数以1为初始值逐个乘以nums集合中的每个元素。
Scala中还有很多操作集合类的方法,将在接下来的章节进行阐述。
Tuples
你可以将异构的元素集合放在Tuples元组中。Tuple中可以存在的元素在2到22个之间(上下界包含在内)。举个例子:
class Person(var name : String)
你可以创建一个包含三个不同类型元素的元组:
val t = (11, "Eleven", new Person("Eleven"))
你可以想下面那样安装数字获取元素:
t._1
t._2
t._3
或者将tuple赋给多个变量:
val (num, string, person) = (11, "Eleven", new Person("Eleven"))
本文还没有展示的内容
尽管我们已经用了差不多10页的篇幅粗略地介绍了Scala,但是这里依赖存在很多东西没有被涉及,包括:
- Strings 和 内置的数值类型
- 包和导入
- 在Scala中怎么使用Java集合类
- 在Scala中使用Java类库
- 构建Scala项目
- 单元测试
- 写Scala脚本
- Maps、Sets 和其它集合类
- 面向对象编程
- 函数式编程
- 并发
- 等等