Scala的第一步

时间:2023-01-14 13:14:46

  

第一步:学习使用Scala解释器

开始Scala最简单的方法是使用Scala解释器,它是一个编写Scala表达式和程序的交互式“shell”。在使用Scala之前需要安装Scala,可以参考 First Steps to Scala 内容。

你可以在命令提示符里输入scala使用它:

$ scala Welcome to Scala version 2.9.2.

Type in expressions to have them evaluated.

Type :help for more information.

scala>

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

scala>  + 

解释器会打印:

res0: Int = 3

这行包括:

 一个自动产生的或用户定义的名称说明计算的值(res0,表示结果0),
 一个冒号(:),跟着表达式的类型(Int),

 一个等号(=),
 计算表达式所得到的结果(3)。

Int类型指代了scala包的类Int。Scala里的包与Java里的包很相似:它们把全局命名空间分区并提供了信息隐藏的机制。类Int的值对应着Java的int值。
第二步:定义一些变量类Int的值对应着Java的int值。更广泛意义上来说,所有的Java原始类型在scala包里都有对应的类。例如,scala.Boolean对应着Java的boolean。

scala.Float对应着Java的float。当你把你的Scala代码编译成Java字节码,Scala编译器将使用Java的原始类型以便获得其带来的性能益处。 resX识别符还将用在后续的代码行中。例如,既然res0已在之前设为3,res0 * 3就是9:

scala> res0 * 3
res1: Int = 9

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

scala> println("Hello, world!")
Hello, world!

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

第二步:定义一些变量

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

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

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

因为Scala具有自动理解你省略的类型的能力,即 类型推断:type inference。Scala解释器(或编译器)可以推断类型。不过,如果你愿意,也可以显式地定义类型,也许有些时候你也应该这么做。显式的类型标注不但可以确保Scala编译器推断你倾向的类型,还可以作为将来代码读者有用的文档。与之不同的是,Scala里变量的类型在其名称之后,用冒号分隔。如:

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

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

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

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

scala> println(msg)
Hello, world!

你对msg不能做的,就是再给它赋值,因为是val而不是var。尝试给msg赋新值会报错:

scala> msg = "Goodbye cruel world!"
<console>:: error: reassignment to val
msg = "Goodbye cruel world!"

如果需要可重复赋值的变量,则必须使用var来定义。如:

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

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

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

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

scala> val oops =
|
|
You typed two blank lines. Starting a new command.
scala>

第三步:定义一些函数

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

scala> def max(x: Int, y: Int): Int = if (x < y) y else x
max: (Int,Int)Int

函数的定义用def开始。函数名,本例中是max,跟着是括号里带有冒号分隔的参数列表。每个函数参数后面必须带前缀冒号的类型标注,因为Scala编译器没办法推断函数参数类型,在max参数列表的括号之后你会看到另一个“: Int”类型标注。这个东西定义了max函数的结果类型:result type跟在函数结果类型之后的是一个等号和一对包含了函数体的大括号。

在函数体前的等号提示我们函数式编程的世界观里,函数定义一个能产生值的表达式。函数的基本结构在下图里面演示:

Scala的第一步

                    Scala函数的基本构成

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

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

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

scala> max(, )
res6: Int =

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

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

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

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

scala> :quit
$

第四步:编写一些Scala脚本

尽管Scala的设计目的是帮助程序员建造非常大规模的系统,但它也能很好地缩小到做脚本的规模。脚本就是一种经常会被执行的放在文件中的句子序列。把以下代码放在hello.scala文件中:

println("Hello, world, from a script!")

然后运行

$ scala hello.scala

于是你又会得到另外的祝词

Hello, world, from a script!

通过Scala的名为args的数组可以获得传递给Scala脚本的命令行参数。Scala里,数组以零开始,通过在括号里指定索引访问一个元素。所以Scala里数组steps的第一个元素是steps(0),不是像Java里的steps[0]。作为测试,输入以下内容到新文件helloarg.scala:

// 向第一个参数打招呼

println("Hello, " + args(0) + "!")

然后运行:

$ scala helloarg.scala planet

这条命令里,"planet"被作为命令行参数传递,并在脚本里作为args(0)被访问。因此,你会看到:

Hello, planet!

注意这个脚本包括了一条注释。Scala编译器将忽略从//开始到行尾截止的以及在/*和*/之间的字符。本例还演示了String使用+操作符的连接。这与你的预期一样。表达式"Hello, "+"world!"将产生字符串"Hello, world!"。

第五步:用while循环;用if判断

要尝试while,在printargs.scala文件里输入以下代码:

var i =
while (i < args.length) {
println(args(i))
i +=
}

注意 虽然本节的例子有助于解释while循环,但它们并未演示最好的Scala风格。在下一段中,你会看到避免用索引枚举数组的更好的手段。

这个脚本开始于变量定义,var i = 0。类型推断认定i的类型是scala.Int,因为这是它的初始值的类型,0。下一行里的while结构使得代码块(大括号之间的代码)重复执行直到布尔表达式i < args.length为假。args.length给出了args数组的长度。代码块包含两句话,每个都缩进两个空格,这是Scala的推荐缩进风格。第一句话,println(args(i)),输出第i个命令行参数。第二句话,i += 1,让i自增一。注意Java的++i和i++在Scala里不起作用,要在Scala里自增,必须写成要么i = i + 1,或者i += 1。用下列命令运行这个脚本:

$ scala printargs.scala Scala is fun

你将看到:

Scala is fun

注意Scala和Java一样,必须把while或if的布尔表达式放在括号里。(换句话说,就是不能像在Ruby里面那样在Scala里这么写:if i < 10。在Scala里必须写成if (i < 10)。)另外一点与Java类似的,是如果代码块仅有一个句子,大括号就是可选的,

并且尽管你没有看到,Scala也和Java一样使用分号分隔句子的,只是Scala里的分号经常是可选的。

第六步:用foreach和for枚举

尽管或许你没意识到,在前一步里写while循环的时候,你正在用指令式:imperative风格编程。指令式风格,是你常常使用像Java,C++和C这些语言里用的风格,一次性发出一个指令式的命令,用循环去枚举,并经常改变共享在不同函数之间的状态,

Scala允许你指令式地编程,但随着你对Scala的深入了解,你可能常会发现你自己在用一种更函数式:functional的风格编程。

函数式语言的一个主要特征是,函数是第一类结构,这在Scala里千真万确。举例来说,另一种(简洁得多)打印每一个命令行参数的方法是:

args.foreach(arg => println(arg))

这行代码中,你在args上调用foreach方法,并把它传入函数。此例中,你传入了带有一个叫做arg参数的函数文本:function literal。函数体是println(arg)。如果你把上述代码输入到新文件pa.scala,并使用命令执行:

$ scala pa.scala Concise is nice

你会看到:

Concise
is
nice

如果你更喜欢简洁的而不是显式的风格,就可以充分体会到Scala特别简洁的优越性。如果函数文本由带一个参数的一句话组成,你都不需要显式命名和指定参数。11
这样,下面的代码同样有效:

args.foreach(println)

总而言之,函数文本的语法就是,括号里的命名参数列表,右箭头,然后是函数体。语法演示在下图中

Scala的第一步

为了努力引导你向函数式的方向,Scala里只有一个指令式for(称为for表达式:expression)的函数式近似。创建一个新文件forargs.scala,输入以下代码:

for (arg <- args)
println(arg)

这个表达式里“for”之后的括号包含arg<-args。<-右侧的是熟悉的args数组。<-左侧的是“arg”,val的名称(不是var)。(因为总归是val,你只要写arg就可,不要写成val arg。)尽管arg可能感觉像var,因为他在每次枚举都会得到新的值,但它的确是val : arg不能在for表达式的函数体中重新赋值。取而代之,对每个args数组的元素,一个新的arg val将被创建并初始化为元素值,然后for的函数体将被执行。

你可以认为<-符号代表“其中”。如果要读for(arg<-args),就读做“对于args中的arg”。

如果执行forargs.scala脚本:

$ scala forargs.scala for arg in args

可以看到:

for
arg
in
args

Scala的第一步的更多相关文章

  1. PySpark初级教程——第一步大数据分析&lpar;附代码实现&rpar;

    概述 数据正以前所未有的速度与日俱增 如何存储.处理和使用这些数据来进行机器学习?spark正可以应对这些问题 了解Spark是什么,它是如何工作的,以及涉及的不同组件是什么 简介 我们正在以前所未有 ...

  2. 开发thinkphp的第一步就是给Application目录&lpar;不包括其下的文件&rpar;777权限&comma; 关闭selinux

    开发thinkphp的时候, 总是会出现各种个样 的奇怪的毛病, 比如: 说什么Application目录不可写, 比如: 说什么 _STORAGE_WRITE_ERROR, 不能生成 Runtime ...

  3. ElasticSearch第一步-环境配置

    ElasticSearch第一步-环境配置 ElasticSearch第二步-CRUD之Sense ElasticSearch第三步-中文分词 ElasticSearch第四步-查询详解 Elasti ...

  4. UE4蓝图编程的第一步

    认识UE4蓝图中颜色与变量类型: UE4中各个颜色对应着不同的变量,连接点和连线的颜色都在表示此处是什么类型的变量.对于初学者来说一开始看到那么多连接点, 可能会很茫然,搞不清还怎么连,如果知道了颜色 ...

  5. STM32F407第一步之点亮LED

    STM32F407第一步之点亮LED. 要点亮LED,首先了解一下F4的GPIO模块.首先看一下STM32F4数据手册,GPIO模块的内部结构图 看上去有点复杂,不要怕,慢慢理解就可以了.对外引脚那里 ...

  6. 重制AdvanceWars第一步 -- 搞定地图

    首先来聊下高级战争吧Advance Wars,由任天堂旗下的Intelligent Systems开发的战棋游戏.初作诞生于GBA上,后来继续跟进了高战2黑洞崛,而后在下一代掌机DS上也出了三代续作高 ...

  7. 高德携手阿里云发布&OpenCurlyDoubleQuote;LBS云”,账户打通只是第一步

    位置.游戏.视频,是公认的基于云计算的三大移动端应用方向.而今,LBS云有了更多进展,在高价值应用与云平台之间实现了资源打通和融合,高德迈出了实质性的一步. 高德地图副总裁郄建军(左)与阿里云业务总经 ...

  8. 005&period;TCP--拼接TCP头部IP头部,实现TCP三次握手的第一步&lpar;Linux,原始套接字&rpar;

    一.目的: 自己拼接IP头,TCP头,计算效验和,将生成的报文用原始套接字发送出去. 若使用tcpdump能监听有对方服务器的包回应,则证明TCP报文是正确的! 二.数据结构: TCP首部结构图: s ...

  9. Theano2&period;1&period;2-基础知识之第一步:代数

    来自:http://deeplearning.net/software/theano/tutorial/adding.html Baby Steps - Algebra 一.两个标量相加 在学习the ...

随机推荐

  1. isEmpty和isBlank的区别

    isEmpty  判断某字符串是否为空,为空的标准是 str==null或 str.length()==0 StringUtils.isEmpty(null) = true StringUtils.i ...

  2. Eclipses使用小技巧

    1.新导入Eclipse的项目,显示很多错误,一般是因为没有加上对应的Lib,添加后错误消失. 2.如果还有错误,而且是与JavaEE相关的,比如说HttpServlet类找不到,更新一下tomcat ...

  3. 迭代器和for-of循环 顺便带一下Es5中的&period;map遍历

    let set = new Set(); //set方法去除重复的数据 [1, 2, 3, 4, 2, 8, 4].map(function (elem) { set.add(elem); //遍历完 ...

  4. Cubieboard2裸机开发之(三)C语言操作LED

    前言 前面通过汇编语言点亮LED,代码虽然简单,但并不是很直观.这次使用熟悉的C语言来控制LED,但是需要注意的地方有两点,第一,要想使用C语言,首先需要在调用C语言代码之前设置好堆栈:第二,调用C语 ...

  5. Twitter数据抓取

    说明:这里分三个系列介绍Twitter数据的非API抓取方法.有兴趣的QQ群交流: BitCrawler网络爬虫QQ群 322937592 1.Twitter数据抓取(一) 2.Twitter数据抓取 ...

  6. Python Requests&colon; Invalid Header Name 解决方法

    这几天在练习python,并且用到了Requests,不得不说真的比urllib 方便了很多啊,简直有点事半功倍的感觉 言归正传,(好像上面的话也没多歪啦~~~~~) 简单叙述下我的script 流程 ...

  7. 使用163&period;com邮箱发送邮件

    不要直接使用登录的密码,而是用配置中的授权码做为密码

  8. Thymeleaf常用th标签

    https://www.jianshu.com/p/f9ebd23e8da4 关键字 功能介绍 案例 th:id 替换id <input th:id="'xxx' + ${collec ...

  9. splash

    function main(splash, args) splash.images_enabled = false //不加载图片 assert(splash:go(args.url)) assert ...

  10. fastjson的&commat;JSONField注解

    @JSONField作用:在字段和方法上1.Field:@JSONField作用在Field时,name可以定义输入key的名字,反序列化的时 值不会赋值到属性上2.作用在setter和getter方 ...