频道栏目
首页 > 网络 > 云计算 > 正文
快学Scala笔记
2017-03-07 09:31:00      个评论    来源:l362321779的博客  
收藏   我要投稿

快学Scala笔记

基础

声明值和变量

在 Scala中,变量或函数的类型总是写在变量或函数名称的后面。
val greeting: String = null
val greeting: Any = "Hello"
Java最大的区别:
Java:String greeting = "hello"
Scala: val greeting: String = "hello"
也可以将多个变量名放在一起声明:
val xmax, ymax = 100
var greeting, message: String = null

常用类型

Scala有七种数值类型:Byte, Char, Short, Int, Long, Float, Double和 Boolean。跟Java不同的是,这些类型是类。Scala并不可以区分基本类型和引用类型。

你可以对数字执行方法,例如:
1.toString() // 产出字符串“1”
或者,可以产出一个Range类:
1.to(10) // 产出 Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

Scala用底层的 java.lang.String类来表示字符串。不过,它通过 StringOps类给字符串追加了上百种操作。
举例来说,intersect("world") //输出 lo
在这个表达式中,java.lang.String对象"Hello"被隐式地转换成了一个StringOps对象,接着StringOps类的intersect方法被应用。

在 Scala中,不需要包装类型。在基本类型和包装类型之间的转换是 Scala编译器的工作。举例来说,如果你创建一个 Int的数组,最终在虚拟机中得到的是一个 int []数组。

在 Scala中,类型转换使用的是方法,而不是强制类型转换。举例来说,99.44.toInt的到99, 99.toChar得到c。toString可以将任意的对象转换成字符串。
要将包含了数字的字符串转换成数值,使用toInt或者toDouble。例如,"99.44".toDouble得到99.44

算术操作符和重载

Scala中,+-*/%等操作符实际上是方法,例如:
a + b
是下面方法调用的简写:
a.+(b)
这里的+是方法名。Scala中几乎可以用任何符号来命名方法

通常来说,你可以用a 方法 b来代替 a.方法(b)例如:
1.to(10)
可以简写成
1 to 10

Scala中没有提供++和--操作符。我们需要使用 +=1或者-=1
counter +=1

对于BigInt和BigDecimal对象,可以用常规的方式使用数学操作符:
val x: BigInt = 1234567890
x * x * x // 产出 1881676371789154860897069000
在 Java中,同样的操作需要写成 x.multiply(x).multiply(x)

调用函数和方法

除了方法之外,Scala还提供函数。相比 Java,在Scala中使用数学函数(比如min或者pow)更为简单——你不需要从某个类调用它的静态方法。
import scala.math._ // 在Scala中,_字符是“通配符”,类似于Java中的*
sqrt(2) // 产出1.4142135623730951
pow(2, 4) // 产出16.0
min(3, Pi) // 产出3.0

使用以 scala.开头的包时,我们可以省去 scala前缀。例如, import math._等同于 import scala.math._。而 math.sqrt(2)等同于 scala.math.sqrt(2)。

不带参数的Scala方法通常不适用括号。 例如,StringOps类的API显示它有一个不带()的distinct方法,起作用是获取字符串中不重复的字符,调用方法如下:
"Hello".distinct
一般来讲,没有参数且不改变当前对象的方法不带圆括号。

apply方法

在Scala,我们通常都会使用类似函数调用的语法。举例来说,如果s是一个字符串,那么s(i)就是该字符串的第i个字符。(在C++中,你会写 s[i];而在Java中,你会这样写: s.charAt(i)。
在REPL中运行如下代码:
"Hello"(4) // 将会产出 'o'
你可以把这种用法当作是()操作符的重载形式,它背后的实现原理是一个名为apply的方法。举例来说,在StringOps类的文档中,你会发现这样一个方法:
def apply(n: Int): Char
也就是说,"Hello(4)是"Hello".apply(4)的简写

如果你看BigInt的半生对象的文档,就会看到让你将字符串或数字转换为BigInt对象的apply方法。举例来说:
BigInt("1234567890")
是如下语句的简写:
BigInt.apply("1234567890"
这个语句产出一个新的BigInt对象,不需要使用new。例如:
BigInt("1234567890") * BigInt("1123458111321")
像这样使用半生对象的apply方法是Scala种构件对象的常用手法。例如,Array(1, 4, 9, 16)返回一个数组,用的就是Array半生对象的apply方法。

控制结构和函数

条件表达式

Scala的 if/else语法结构和Java一样。不过在Scala中 if/else表达式有值,这个值就是跟在if或else之后的表达式的值。例如:
if(x > 0) 1 else -1
上述表达式的值是 1或 -1,具体是哪一个取决于 x的值。你可以将 if/else表达式的值赋值给变量:
val s = if(x > 0) 1 else -1
这与如下语句的效果一样:
if( x > 0) s = 1 else s = -1
不过,第一种写法更好,因为它可以用来初始化一个val。而在第二种写法当中,s必须是var

在Java和C中,有一个 ?:操作符,可以表达同样的目的:
x > 0 ? 1 : -1
等同于 Scala表达式 if( x > 0) 1 else -1。不过,在Scala中你不能在 ?:中插入语句。 Scala中的if / else将在Java和C中分开的两个语法结构 if/else和 ?:结合在了一起。
在Scala中,每个表达式都有一个类型。举例来说,表达式 if(x > 0) 1 else -1的类型是Int,因为两个分支的类型都是Int。if(x > 0) "positive" else -1这个表达式的类型是两个分支类型的公共超类型。在本例中,其中一个分支是 java.lang.String,而另一个分支是 Int,它们的公共超类型叫做 Any。

如果else部分缺失了,比如:
if( x > 0) 1
那么有可能if语句没有输出值。但是在Scala中,每个表达式都应该有某种值。这个问题的解决方案是引入一个Unit类,写作()。这样,不带else的语句等同于
if( x > 0) 1 else ()
你可以把 ()当作是表示“无有用值”的占位符。将Unit当作Java或C中的void

语句终止

Scala不需要每行都以分号结尾,但是,如果想在单行中写下多个语句,就需要将它们用分号隔开。例如:
if(n > 0) {r = r * n; n -= 1}
如果在写的语句比较长,需要分两行来写的话,就要确保第一行以一个不能用做语句结尾的符号结尾。通常来说一个比较好的选择是操作符:
s = s0 + (v - v0) * t + // +告诉解析器这里不是语句的末尾
0.5 * (a - a0) * t * t

块表达式和赋值

在Scala中,{}块包含一系列表达式,其结果也是一个表达式。块中最后一个表达式的值就是块的值。
这个特性对于那种对某个val的初始化需要分多部完成的情况很有用。例如:
val distance = {val dx = x - x0; val dy = y - y0; sqrt(dx * dx + dy * dy)}
{}块的值取自最后一个表达式的值,即sqrt(dx * dx + dy * dy)

Scala中,赋值动作本身是没有值的——或者,更严格的说,他们的值是Unit类型。Unit类型等同于Java和C中的void,而这个类型只有一个值,写作()
一个以赋值语句结束的块,比如:
{r = r * n; n -= 1}
的值是Unit类型的。
x = y = 1 // 别这样做
y =1的值是(),x为()没什么意义

输入和输出

打印一个值到屏幕,使用print和println函数。
print("Answer: )
println(42)
等同于
println("Answer: + 42)
另外,还有一个带有C风格的格式化字符串的printf函数:
printf("Hello, %s! You are %d years old.\n", "Fred", 42)

可以使用readLine函数从控制台读取一行输入。如果要读取数字、Boolean或者是字符,可以用readInt、readDouble、readByte、readShort、readLong、readFloat、readBoolean或者readChar。与其他方法不同,readLine带一个参数作为提示字符串:
val name = readLine("Your name: ")
print("Your age: ")
val age = readInt()
printf("Hello, %s! Next year, you will be %d.\n", name, age, age + 1)

循环

Scala拥有与Java和C相同的while和do循环
”while(n > 0){
” r = r * n
” n -= 1
”}

Scala没有与for(初始化变量;检查变量是否满足某条件;更新变量)循环直接对应的结构。如果你需要这样的循环,有两个选择:一是使用while循环,二是使用如下for语句:
” for(i <- 1 to n)
” r = r * i
RinchInt这个类的to方法会返回1到数字n的Range

下面这个语法结构
for(i <- 表达式)
让变量i遍历<-右边的表达式的所有值。至于这个遍历具体如何执行,则取决于表达式的类型。对于Scala集合比如Range而言,这个循环会让依次取得区间中的每个值。
在for循环的变量之前没有val或者var的指定。该变量的类型是集合的元素类型。循环变量的作用域一直持续到循环结束。

遍历字符串或者数组时,你通常需要使用从0到n-1的区间。这个时候你可以用until方法而不是to方法。until方法返回一个并不包含上限的区间。
val s = "Hello"
var sum = 0
for(i <- 0 until s.length) // i的最后一个取值是 s.length-1
sum += s(i)
在这个例子中,我们其实并不需要使用下标。你可以直接遍历对应的字符序列:
var sum = 0
for(ch <- "Hello") sum += ch
在Scala中,对循环的使用并不如其他语言那么频繁。我们通常可以通过对序列中的所有值应用某个函数的方式来处理它们,而完成这项工作只需要一次方法调用。

Scala并没有提供break或continue语句来退出循环。那么如果需要break时我们应该怎么做呢?有以下几个选项:
”1. 使用Boolean型控制变量
”2. 使用嵌套函数——你可以从函数当中return
”3. 使用 Break对象中的 break方法:
” import scala.until.control.Breaks._
” breakable{
” for(…){
” if(…) break; // 退出breakable块
” …
” }
” }
”在这里,控制权的转移是通过抛出和捕获异常完成的。因此,如果时间很重要的话,你应该尽量避免使用这套机制

高级for循环和for推导式

你可以用变量 <- 表达式的形式提供多个生成器,用分号将它们隔开。例如:
for(i <- 1 to 3; j <- 1 to 3) print ((10 * i + j) + " " // 将打印 11 12 13 21 22 23 31 32 33
每个生成器都可以带一个守卫,以if开头的 Boolean表达式:
for(i < 1 to 3; j < - 1 to 3 if i != j) print ((10 * i + j) + " ") // 将打印12 13 21 23 31 32
注意在if之前并没有分号
你可以使用任意多的定义,银日可以在循环中使用的变量:
for(i <- 1 to 3; from = 4 - i; j <- from to 3) print ((10 * i + j) + " ") // 将打印 13 22 23 31 32 33
如果for循环的循环体以 yield开始,则该循环会构造出一个集合,每次迭代生成集合中的一个值:
for(i <- 1 to 10) yield i % 3 // 生成 Vector(1, 2, 0, 1, 2, 0, 1, 2, 0, 1)
这种循环叫做 for推导式。
for推导式生成的集合与它的第一个生成器的类型是兼容的

点击复制链接 与好友分享!回本站首页
上一篇:centos7制作本地源
下一篇:Spark算子执行流程详解之七
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站