初探Scala编程:解释器,变量及函数定义

开发 后端
本文节选自Martin Odersky,Lex Spoon和Bill Venners所著,Regular翻译的《Programming in Scala》的第二章。Scala是一种针对 JVM 将函数和面向对象技术组合在一起的编程语言。

在我们开始深度Scala教程之前,我们将用两章来给你画一张Scala大致的图纸,更重要的是,带你写一些代码。我们鼓励你实际尝试所有出现在本章以及后续章节中的代码例子。开始学习Scala***的方法就是用它编程。

51CTO编辑推荐:Scala编程语言专题

要执行本章的例子,你应该有一份标准的Scala安装。想要的话,可以到http://www.scala-lang.org/downloads并依照你的平台的向导。你也可以使用Eclipse,IntelliJ,或NetBeans的Scala插件,但是对于本章的这几步来说,我们假设你用的是从scala-lang.org拿到的Scala发布包。

***步:学习使用Scala解释器

开始Scala最简单的方法是使用Scala解释器,它是一个编写Scala表达式和程序的交互式“shell”。简单地在解释器里输入一个表达式,它将计算这个表达式并打印结果值。Scala的交互式shell就叫做scala。你可以在命令提示符里输入scala使用它:

  1. $ scala  
  2. Welcome to Scala version 2.7.2.  
  3. Type in expressions to have them evaluated.  
  4. Type :help for more information.  
  5. scala> 

在你输入表达式,如1 + 2,并敲了回车之后:

  1. scala> 1 + 2 

解释器会打印:

  1. res0: Int = 3 

这行包括:

一个自动产生的或用户定义的名称说明计算的值(res0,表示结果0),

一个冒号(:),跟着表达式的类型(Int),

一个等号(=),

计算表达式所得到的结果(3)。

Int类型指代了scala包的类Int。Scala里的包与Java里的包很相似:它们把全局命名空间分区并提供了信息隐藏的机制。 类Int的值对应着Java的int值。更广泛意义上来说,所有的Java原始类型在scala包里都有对应的类。例如,scala.Boolean对应着Java的boolean。scala.Float对应着Java的float。当你把你的Scala代码编译成Java字节码,Scala编译器将使用Java的原始类型以便获得其带来的性能益处。

resX识别符还将用在后续的代码行中。

例如,既然res0已在之前设为3,res0 * 3就是9:

  1. scala> res0 * 3  
  2. res1: Int = 9 

打印必要的,却不仅此而已的,Hello, world! 贺词,输入:

  1. scala> println("Hello, world!")  
  2. Hello, world! 

println函数在标准输出上打印传给它的字串,就跟Java里的System.out.println一样。

第二步:定义一些变量

Scala有两种变量,val和var。val类似于Java里的final变量。一旦初始化了,val就不能再赋值了。与之对应的,var如同Java里面的非final变量。var可以在它生命周期中被多次赋值。下面是一个val的定义:

  1. scala> val msg = "Hello, world!" 
  2. msg: java.lang.String = Hello, world!  

这个语句引入了msg当作字串"Hello, world!"的名字。类型是java.lang.String,因为Scala的字串是由Java的String类实现的。

如果你之前曾定义过Java变量,你会发现一个很醒目的差别:无论java.lang.String还是String都没有出现在val的定义中。本例演示了类型推断:type inference,这种Scala能自动理解你省略的类型的能力。在这个例子里,因为你用一个字串文本初始化了msg,Scala推断msg的类型是String。如果Scala解释器(或编译器)可以推断类型,那么让它这么做而不是写一些没必要的显式类型标注常常是***的选择。不过,如果你愿意,也可以显式地定义类型,也许有些时候你也应该这么做。显式的类型标注不但可以确保Scala编译器推断你倾向的类型,还可以作为将来代码读者有用的文档。Java中变量的类型指定在其名称之前,与之不同的是,Scala里变量的类型在其名称之后,用冒号分隔。如:

  1. scala> val msg2: java.lang.String = "Hello again, world!" 
  2. msg2: java.lang.String = Hello again, world!  

或者,因为在Scala程序里java.lang类型的简化名 也是可见的,所以可以简化为:

  1. scala> val msg3: String = "Hello yet again, world!" 
  2. msg3: String = Hello yet again, world! 

回到原来的那个msg,现在它定义好了,你可以按你的想法使用它,如:

  1. scala> println(msg)  
  2. Hello, world!  

你对msg不能做的,因为是val而不是var,就是再给它赋值。 例如,看看你做如下尝试的时候编译器怎么报错的:

  1. scala> msg = "Goodbye cruel world!" 
  2. <console>:5: error: reassignment to val  
  3.          msg = "Goodbye cruel world!" 
  4.               ˆ  

如果可重赋值是你需要的,你应使用var,如下:

  1. scala> var greeting = "Hello, world!" 
  2. greeting: java.lang.String = Hello, world!  

由于greeting是var而不是val,你可以在之后对它重新赋值。比如说,如果你之后心态不平了,你可以修改你的greeting为:

  1. scala> greeting = "Leave me alone, world!" 
  2. greeting: java.lang.String = Leave me alone, world! 

要输入一些能跨越多行的东西,只要一行行输进去就行。如果输到行尾还没结束,解释器将在下一行回应一个竖线。

  1. scala> val multiLine =  
  2.       | "This is the next line."  
  3. multiLine: java.lang.String = This is the next line.  

如果你意识到你输入了一些错误的东西,而解释器仍在等着你更多的输入,你可以通过按两次回车取消掉:

  1. scala> val oops =  
  2.       |  
  3.       |  
  4. You typed two blank lines. Starting a new command.  
  5. scala> 

本书后续部分,我们将省略竖线以便让代码更易于阅读(并易于从PDF电子书中复制粘贴到解释器里)。

第三步:定义一些函数

现在你已经用过了Scala的变量,或许想写点儿函数。下面是在Scala里面的做法:

  1. scala> def max(x: Int, y: Int): Int = {  
  2.      if (x > y) x  
  3.      else y  
  4.     }  
  5. max: (Int,Int)Int  

函数的定义用def开始。函数名,本例中是max,跟着是括号里带有冒号分隔的参数列表。每个函数参数后面必须带前缀冒号的类型标注,因为Scala编译器(还有解释器,但之后我们将只说编译器)没办法推断函数参数类型。本例中,名叫max的函数带有两个参数,x和y,都是Int类型。在max参数列表的括号之后你会看到另一个“: Int”类型标注。这个东西定义了max函数的结果类型:result type。 跟在函数结果类型之后的是一个等号和一对包含了函数体的大括号。本例中,函数体里仅有一个if表达式,选择x或者y,哪个较大,就当作max函数的结果。就像这里演示的,Scala的if表达式可以像Java的三元操作符那样产生一个值。举例来说,Scala表达式“if (x > y) x else y”与Java里的“(x > y) ? x : y”表现得很像。在函数体前的等号提示我们函数式编程的世界观里,函数定义一个能产生值的表达式。函数的基本结构在图2.1里面演示。

Scala函数的基本构成 

有时候Scala编译器会需要你定义函数的结果类型。比方说,如果函数是递归的, 你就必须显式地定义函数结果类型。然而在max的例子里,你可以不用写结果类型,编译器也能够推断它。 同样,如果函数仅由一个句子组成,你可以可选地不写大括号。这样,你就可以把max函数写成这样:

  1. scala> def max2(x: Int, y: Int) = if (x > y) x else y  
  2. max2: (Int,Int)Int  

一旦你定义了函数,你就可以用它的名字调用它,如:

  1. scala> max(3, 5)  
  2. res6: Int = 5 

还有既不带参数也不返回有用结果的函数定义:

  1. scala> def greet() = println("Hello, world!")  
  2. greet: ()Unit  

当你定义了greet()函数,解释器会回应一个greet: ()Unit。“greet”当然是函数名。空白的括号说明函数不带参数。Unit是greet的结果类型。Unit的结果类型指的是函数没有返回有用的值。Scala的Unit类型比较接近Java的void类型,而且实际上Java里每一个返回void的方法都被映射为Scala里返回Unit的方法。因此结果类型为Unit的方法,仅仅是为了它们的副作用而运行。在greet()的例子里,副作用是在标准输出上打印一句客气的助词。

下一步,你将把Scala代码放在一个文件中并作为脚本执行它。如果你想离开解释器,输入:quit或者:q。

  1. scala> :quit  

本文节选自《Programming in Scala》  

【相关阅读】

  1. 影响Scala语言设计的因素列表
  2. 喜欢Scala编程的四个理由
  3. Scala融合面向对象和函数概念的方法
  4. Scala的语言特性——可伸展的语言
  5. 学习Scala中的Case类
责任编辑:杨鹏飞 来源: Artima
相关推荐

2013-09-09 09:41:34

2009-07-08 17:40:28

ScalaScala脚本

2010-03-11 10:34:22

Scala

2009-12-11 10:42:00

Scala讲座类定义构造函数

2009-07-21 17:21:57

Scala定义函数

2009-10-30 10:45:45

ScalaEclipseAndroid

2009-06-16 17:09:17

Scala面向对象函数编程

2009-09-27 15:23:00

Scala讲座函数式编程Scala

2010-09-10 10:23:57

SQL变量赋值

2010-09-14 15:34:41

Scala

2009-07-22 08:34:47

Scala方法和字段

2009-07-08 16:10:24

Scala简介面向对象函数式

2010-11-17 11:31:22

Scala基础面向对象Scala

2014-01-21 09:15:12

Python函数

2009-07-21 16:58:31

Scala变量范围

2020-05-21 07:00:00

软件定义网络SDN网络

2009-08-24 09:46:40

面向切面编程AOP

2010-09-14 13:22:17

Scala编程指南Scala

2009-12-11 10:43:00

Scala讲座操作符函数

2009-09-17 13:05:38

Linq局部变量类型
点赞
收藏

51CTO技术栈公众号