文档章节

Scala学习(二)控制结构和函数

我爱春天的毛毛雨
 我爱春天的毛毛雨
发布于 2018/09/30 11:24
字数 3297
阅读 12
收藏 0

1.条件表达式

Scala的if/else语法结构和Java一样。不过,在Scala中if/else表达式有值,这个值就是跟在if或else之后的表达式的值。例如:

if(x>0) 1 else -1

或者将表达式的值赋值给变量:

val s = if(x>0) 1 else -1

这与如下语句的效果一样:

if(x>0) s = 1 else s = -1

不过,第一种写法更好,因为它可以用来初始化一个val常量。而第二种写法中,s必须是var变量。

--------------------------------

在Scala中if/else有着和Java或者C++的三元表达式相同的功能,例如

x>0 ? 1 : -1 //Java或C++

而在Scala中,我们可以这样:

if(x>0) "hello" else -1

在Scala中每个表达式都有一种类型,表达式的类型可以相同可以不相同,这点与Java有所不同。不同类型表达式的if/else我们称为混合表达式,

接收他们的值或变量的类型为公共类型Any(相当于Java中的Object)

--------------------------------

如果else部分缺失了,例如:

if(x>0) 1

那么可能if没有输出值,但是在Scala中,每个表达式都应该有值。这个问题的解决方案是引入一个Unit类,写做()。不带饿死了的这个if语句等同于

if(x>0) 1 else ()

你可以把()当做“无有用值”的占位符,将Unit当做Java或C++中的void。

注:Scala没有switch语句

注:REPL(解析器)比起编译器来说,它只能够按行执行程序,例如:

if (x > 0) 1 

else if (x == 0) 0 else -1

这时REPL会执行if (x>0) 1 然后显示结果。之后的else他将会报错。

如果你想在else前换行的话,要用花括号:

if (x > 0) {1 

}else if (x == 0) 0 else -1

只有在REPL中才会有这样的顾虑,其他地方大家大可不必担心

提示:如果想在REPL中粘贴成块的代码又不想让REPL按行执行,可以使用粘贴模式。键入

:paste

把代码粘贴进去,然后Ctrl+D。这样REPL就会把代码块当做一个整体分析。

2.语句终止

在Java和C++中,每个语句都要以分号结束。而现在Scala中与JavaScript和其他脚本类似,行位不需要设置分号。同样在}、else以及类似的位置也不必写分号,只要能够从上下文明确的判断出这里语句是终止的即可。

不过,如果你想在单行中写下多个语句,就需要将他们以分号分开。例如:

if(n > 0) { r = r * n; n -=1 }

如果你在写一个较长的语句,需要分两行写的话,就需要确保第一行以一个不能用作语句结尾的符号结尾。通常来说一个比较好的选择是操作符:

s = s0 + (v - v0) * t +       // +来告诉解析器这里不是语句的末尾

0.5 * (a - a0) * t * t

在实际的编码时,长表达式通常涉及函数或方法调用,Scala程序猿更倾向于使用Kernighan&Ritchie风格的花括号

if(n >0){

  r = r * n

  n -= 1

}

以‘{’结束的行很清楚的表达了后面还有内容,直到遇见匹配的‘}’

许多来自Java或C++的程序员一开始并不适应省去分号的做法。如果你更倾向于使用分号,用了就是了,没啥坏处。

3.块表达式和赋值

在Java或C++中,块语句是包含于{}中的语句序列。每当你需要在逻辑分支或循环中放置多个动作时,你都可以使用块语句。

在Scala中,{}块包含一系列的表达式,其中结果也是一个表达式。块中最后一个表达式的值就是块儿的值。

--------------------------------

在Scala中,赋值动作本身是没有值得——或者,更严格地说,他们的值是Unit类型的。你应该记得,Unit类型等同于Java和C++中的void,而这个类型的值只有一个值,写做()。

一个赋值语句结束的块,比如

{r = r * n; n -= 1}

的值是Unit类型的。这没有问题,只是当我们定义函数时需要意识到这一点。

注:由于赋值语句的值是Unit类型的,别把他们串接在一起。

x = y = 1 //别这么做

y = 1 的值是(),你不可能想把一个Unit类型的值赋值给x。(在Java或者C++中,上面的做法是可以做到x、y同时赋值的)

4.输入和输出

如果要打印一个值,我们用print或者println以及printf函数。与Java中的用法相同,这里不做过多解释。

--------------------------------

你可以用readLine函数从控制台读取一行输入。如果要读取数字、Boolean或者是字符,可以用readInt、readDouble、readByte、readShort、readLong、readFloat、readBoolean或者readChar。

与其他方法不同,readLine带一个参数作为提示字符串:

 

5.循环

Scaca中拥有与Java和C++相同的while和do循环。例如:

--------------------------------

Scala中没有与Java相同的for结构:for(初始化变量;检查变量是否满足条件;更新变量)。

在Scala中只有这样的for循环语法:

for(i ← 表达式)      //i不需要定义,也可以所以取名

接下来我们用RichInt类的to方法,去演示Scala中for的用法:

还有另一种遍历方法until,它常用于遍历字符串或者数组,同上面的to方法的例子比较,能看出他们两个的区别

to方法:包含头和尾的遍历(相当于<=)

until方法:包含头不包含尾的遍历(相当于<)

注:遍历字符串的两种方法:

1.用until方法

2.直接遍历

--------------------------------

Scala中并没有提供break或者continue语句来退出循环。如果需要break时我们可以采取如下选项:

  1. 使用Boolean型控制变量
  2. 使用嵌套函数——你可以从函数当中return
  3. 使用Breaks对象中的break方法

break方法使用示例:

 

6.高级for循环和for推导式

Scala中的for循环要比Java功能丰富的多,比如:

1.我们可以在for循环中添加多个 变量←表达式 这种形式的生成器,用分号分隔开:

2.每一个生成器都可以带一个守卫,以if开头的Boolean表达式:注意if前没有分号

3.你可以使用任意多的定义,引入可以在循环中使用的变量

4.如果for循环以yield开始,则该循环会构造出一个集合,每次迭代生成集合中的一个值

这类循环叫做for推导式,for推导式生成的集合与它的第一个生成器的类型是兼容的

7.函数

Scala除了方法还支持函数,方法对对象进行操作,函数不是。C++也有函数,在Java中我们只能通过静态方法来模拟函数。

要定义函数,完整格式如下:

def  [函数名称]([参数名称]:[参数类型]...): [返回值类型] = {

    函数体

}

例如:

def add(x : Int , y : Int) : Int = {

    var z = x + y;

    return z;

}

由于{}块中最后一个表达式的值就是块儿的值。因此我们可以省略return。

def add(x : Int , y : Int) : Int = {

    var z = x + y;

    z;

}

在进一步简化:

def add(x : Int , y : Int) : Int = x + y

在Scala中,只要函数不是递归的,我们就不需要指定返回类型。Scala编译器可以通过 = 右侧的表达式类型推断出返回值类型。因此最终函数简化如下:

def add(x : Int , y : Int)  = x + y

如果是递归函数,我们就必须要指定返回值类型了。

def fac(n : Int) : Int = if(n <= 0) 1 else n * fac( n - 1)

说明:虽然在带名函数中使用return并没有什么不对,但是我们最好适应没有return的日子。很快,你就会使用大量的匿名函数,这些函数中return并不返回值给调用者。

它跳出到包含它的带名函数中。我们可以把return当做是函数版break语句,尽在需要时使用。

8.默认参数和带名参数

我们在调用某些函数时并不显示的给出所有参数值,对于这些函数我们可以使用默认参数值。例如:

def decorate(prefix : String, str : String, suffix : String) = {

    prefix + str + suffix

}

在调用上面的decorate函数的时候我们必须给出所有的参数,否则函数将会执行错误,那如果此时我们只想给出一个参数就能让其运行我们该如何做呢?那就是默认参数值:

def decorate(prefix : String = "[[", str : String, suffix : String = "]]") = {

    prefix + str + suffix

}

我们可以在定义函数入参时先给其赋值,从而做到默认参数值的功能,但是另一个问题又来了,作为程序员我们都知道调用方法或者函数的时候,参数都是按顺序写入的,我们如何做到给指定位置的入参赋值呢?Scala帮我们做到了这一点:

如图,我们可以向表达式一样为指定参数赋值,这样我们就可以无视参数的顺序来调用函数或者方法了,这就是带名参数

9.变长参数

我们知道在Java中,边长参数用 ... 来表示:

public void method(int a ...){

    方法体...

}

而在Scala中,边长参数用* 来表示,比如我们创建一个计算多个数相加的方法,参数不确定。

def add(a : Int*) = {

    var sum = 0;

    for(x <- a) sum += x;

    sum;

}

对于上面的add方法,如果你已经有了一个有值序列,则不能直接将它传入上面的大的方法,比如:

val a = add(1 to 5)  //错误

因为我们的add方法的入参是Int类型的序列,而1 to 5 的类型为:

他并不是add方法的入参类型因此直接传入一定有问题,需要进行类型的转换,那么范围类型如何转换成入参序列呢?Scala中为我们提供了一种语法,追加 :_*

val a = add(1 to 5 :_* )

两种情况对比:

在递归的定义中我们会用到上述语法:

def recursiveSum(args : Int*): Int = {

    if(args.length == 0) 0

    else args.head = recursiveSum(args.tail:_*)

}

在这里,序列的head是他的首个元素,而tail是所有其他元素的序列,这又是一个序列,我们用 :_* 来将它转换成参数序列。

10.过程

Scala对于不返回值得函数有特殊的表示法。如果函数体包含在花括号当中但没有前面的=号,那么返回类型就是Unit。这样的函数被称为过程。过程不返回值,我们调用它仅仅是为了他的辅助作用。

例如:

def out(a : Int){

    print(a)

}

或者我们可以显示声明Unit返回类型:

def out(a : Int): Unit = {

    print(a)

}

11.懒值

当val 被声明为lazy时,他的初始化将被延迟,也就是懒加载,知道我们首次对它进行取值,例如

//在words被定义时取值

val words = scala.io.Source.fromFile("C:\\Users\\Administrator\\Desktop\\wordCount.txt").mkString

//在words被首次使用时取值

lazy val words = scala.io.Source.fromFile("C:\\Users\\Administrator\\Desktop\\wordCount.txt").mkString

//在每一次words被使用时取值

def words = scala.io.Source.fromFile("C:\\Users\\Administrator\\Desktop\\wordCount.txt").mkString

你可以把懒值当做是介于val和def的中间状态

--------------------------------

说明:懒值并不是没有额外开销。我们每次访问懒值,都会有一个方法被调用,而这个方法将会以线程安全的方式检查该值是否已被初始化。

12.异常

Scala的异常工作机制和Java或者C++一样。抛出异常时你可以这样:

throw new Exception("this is a exception")

和Java一样,排出的对象必须是java.lang.Throwable的子类。不过,与Java不同的是,Scala没有“受检”异常,你不需要声明说函数或方法可能抛出某种异常。

--------------------------------

throw表达式有特殊的返回类型Nothing。比如:

if(x >= 0){

    sqrt(x)

}else throw new IllegalArgumentException(" x should not be negative")

第一个分支类型为Double,第二个分支类型为Nothing。因此,if/else表达式的类型是Double

--------------------------------

捕获异常的语法采用的是模式匹配的语法

try{

    "Hello".toInt

} catch {

    case _ : Exception       => println("xxxxxxx")

    case ex : IOException => ex.printStackTrace()

}

和Java或C++一样,更通用的异常应该排在更具体的异常之后。

如果你不需要使用捕获的异常对象,可以使用_来代替变量名。

--------------------------------

try/finally语句让你可以释放资源,不论有没有发生异常。这点和Java一样。

我们也可以下车和Java中一样的try/catch/finally语句:

try{...}catch{...}finally{...}

© 著作权归作者所有

我爱春天的毛毛雨
粉丝 5
博文 48
码字总数 114206
作品 0
鸡西
私信 提问
Scala控制结构、函数式编程解析讲解

首先,Scala的基本控制结构包括顺序、条件、循环控制结构三种方式,这和其他的JVM语言是一致的,但是Scala存在一些高级控制结构类模式匹配。 主要有if、for、while三种控制结构方式: 一、i...

csdn5215的博客
2017/12/16
0
0
Spark(三):弹性分布式数据集(RDD)

一:Scala Scala 是一门现代的多范式编程语言,志在以简练、优雅及类型安全的方式来表达常用编程模式。它平滑地集成了面向对象和函数语言的特性。Scala 运行于 Java 平台(JVM,Java 虚拟机)...

牧羊人Berg
2016/06/02
405
0
spark (二)

说明: 要在本地运行spark,因为spark是用scala语言写的,运行在JVM上面,你要做的只是安装java 6及以上版本就够了。 2.1 下载spark 访问http://spark.apache.org/downloads.html 的apache ...

KongFanhao
2016/06/20
44
0
Scala学习--《Scala编程》

Scala学习手册--可伸缩的语言(随着使用者的需求而成长) 第一章:基本概念 Scala=FP+OO、静态语言 兼容性、简短、高层级抽象、高级的静态类别、伸缩性 兼容:与Java兼容,可无缝实施互操作。...

hanzhankang
2014/02/15
257
0
【scala初学】scala 控制 for while match if

上一章我们共同研究了for循环以及变种。这章我们围绕比较常用的几个其他控制语句学习。 首先,对for进行补充, For-Comprehensions 格式: for (s ) yield e 举例: var range = 0.until(10...

yjplxq
2014/05/17
0
0

没有更多内容

加载失败,请刷新页面

加载更多

基于CentOS7搭建GitLab

基于CentOS7搭建GitLab 12018.11.02 16:38:51字数 959阅读 3791 本文作者:蓝雄威,叩丁狼高级讲师。原创文章,转载请注明出处。 一、简介 Git Lab GitLab是利用 Ruby on Rails 一个开源的版...

linjin200
9分钟前
2
0
random生成随机数

随机生成0到100之间的10个随机数,然后使用冒泡排序将这10个数按从小到大的顺序排序 生成10个随机数 import randomnum = range(0, 100) # 范围在0到100之间,需要用到range()函数。nums...

彩色泡泡糖
13分钟前
1
0
kubernetes 环境搭建 —— kubeadm

主从节点需要安装的服务 Master 节点 Node 节点 etcd-master Control plane(如:calico,fannel) kube-apiserver kube-proxy kube-controller-manager other apps kube-dns Control plane(如:......

lemos
16分钟前
1
0
php将字符串中的中英文数字分割

$str = "php如何将字 符串中322的字母数字Asf f45d和中文_分割?"; $arr = preg_split("/([a-zA-Z0-9]+)/", $str, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); print_r($arr); Arr......

小小小壮
16分钟前
1
0
茑屋书店理解(一)

说到实体书店,你可能会想到两个字“难做”。一是电子书大为盛行,二是纸书作为标准品,完全可以在网上购买,因此国内许多实体书店的日子是举步维艰。但是在日本有这么一家实体书店,目前已经...

Idea
19分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部