Scala笔记一

保留字

保留字说明
abstract抽象声明
casematch表达式中的case子句;定义一个case类
catch捕捉抛出的异常
class声明一个类
def定义一个方法
do用于do…while循环
else与if配对的else语句
extends表示接下来的class或trait是所声明的class或trait的父类型
falseBoolean的false值
final用于class或trait,表示不能派生子类型;用于类型成员,则表示派生的class或trait不能覆写它
forfor循环
forSome用在已存在的类型声明中,限制其能够使用的具体类型
ifif语句
implicit使得方法或变量值可以被用于隐含转换;将方法参数标记为可选的,只要在调用该方法时,作用域内有类型匹配的候选对象,就会使用该对象作为参数
import将一个或多个类型抑或类型的成员导入到当前作用域
lazy推迟val变量的赋值
match用于类型匹配语句
new创建类的一个实例
null尚未被赋值的引用变量的值
object用于单例声明,单例是只用一个实例的类
override当原始成员未被声明为final时,用override覆写类型中的一个具体成员
package声明包的作用域
private限制某个声明的可见性
protected限制某个声明的可见性
requires停用,以前用于子类型
return从函数返回
sealed用于父类型,要求所有派生的子类型必须在同一个源文件中声明
super类似this,单表示父类型
this对象指向自身的引用;辅助构造函数的方法名
throw抛出异常
trait这是一个混入模块,对类的实例添加额外的状态和行为;也可以用于声明而不实现方法.类似java的interface
try将可能抛出异常的代码块包围起来
trueBoolean的true值
type声明类型
val声明一个”只读”变量
var声明一个可读可写的变量
while用于while循环
with表示所声明的类或实例化的对象包括后面的trait
yield在for循环中返回元素,这些元素会构成一个序列
_ (下划线)占位符,使用imort,函数字面量中
:分隔标识符和类型注解
=赋值
=>在函数字面量中分隔参数列表与函数体
<-在for循环中的生成表达式
<:在参数化类型和抽象类型声明中,用于限制允许的类型
<%在参数化类型和抽象类型的view bound生命中
:
在参数化类型和抽象类型生命中,用于限制允许的类型
#在类型注入中使用
@注解

Scala不存在breakcontinue关键字

分号

  • 分号是表达式之间的间隔
  • 当一行结束时,Scala就认为表达式结束了,除非它可以判断出该表达式尚未结束

变量声明

  • Scala允许声明变量是可变的还是不可变的
  • 声明不可变变量使用val
  • 声明可变变量使用var
// 声明不可变变量,这里只是array不可再更改,但是数组内容可以更改
val array:Array[String] = new Array(5)
// 可变
var price: Double = 1.1

Range

  • 生成从某个起点到某个终点的一个数字序列
  • 支持Int, Long, Float, Double, Char, BigInt, BigDecimal
  • 使用to包括区间上限
  • 使用until不包括区间上限
  • 使用by设置步长
scala> 1 to 5
res2: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5)

scala> 1 until 5
res3: scala.collection.immutable.Range = Range(1, 2, 3, 4)
scala> 1 to 10 by 3
res0: scala.collection.immutable.Range = Range(1, 4, 7, 10)

scala> 0.1f to 5.3f by 1.0f
res1: scala.collection.immutable.NumericRange[Float] = NumericRange(0.1, 1.1, 2.1, 3.1, 4.1, 5.1)

scala> 'a' to 'g'
res2: scala.collection.immutable.NumericRange.Inclusive[Char] = NumericRange(a, b, c, d, e, f, g)

scala> BigInt(1) to BigInt(5) by 2
res3: scala.collection.immutable.NumericRange[BigInt] = NumericRange(1, 3, 5)

偏函数

  • 不处理所有可能的输入,只处理那些能与至少一个case语句匹配的输入
  • 在偏函数中,只能使用case语句
  • 整个函数必须用花括号包围
  • 如果偏函数被调用,而函数的输入却与所有语句都不匹配,系统就会抛出一个MatchError运行时错误
  • 使用isDefineAt方法测试特定输入是否与偏函数匹配
  • 偏函数链式连接: pf1 orElse pf2 orElse pf3 … 只有所有偏函数都不匹配,才会抛出MatchError

示例

代码

// file: pf.scala
var pf1: PartialFunction[Any, String] = { case s: String => "YES"}
var pf2: PartialFunction[Any, String] = { case d: Double => "YES"}

val pf = pf1 orElse pf2

def tryPF(x: Any, f: PartialFunction[Any, String]): String =
    try {f(x).toString} catch {case _: MatchError => "ERROR!"}

def d(x: Any, f: PartialFunction[Any,String]) =
    f.isDefinedAt(x).toString

println("      |   pf1 - String |   pf2 - Double  |   pf - All")
println("x     | def?  | pf1(x) | def?   | pf2(x) | def?  |  pf(x)")
println("+" * 50)
List("str", 3.14, 10) foreach {
    x => printf("%-5s | %-5s | %-6s | %-6s | %-6s | %-5s | %-6s\n", x.toString, d(x, pf1), tryPF(x, pf1),
        d(x, pf2), tryPF(x, pf2), d(x, pf), tryPF(x, pf))
}

运行

scala pf.scala

运行结果

      |   pf1 - String |   pf2 - Double  |   pf - All
x     | def?  | pf1(x) | def?   | pf2(x) | def?  |  pf(x)
++++++++++++++++++++++++++++++++++++++++++++++++++
str   | true  | YES    | false  | ERROR! | true  | YES   
3.14  | false | ERROR! | true   | YES    | true  | YES   
10    | false | ERROR! | false  | ERROR! | false | ERROR!

方法声明

方法默认值和命名参数列表

  • 可以为方法参数提供默认值
  • 调用方法时可以只提供部分参数值,可以只传入指定参数

示例

代码
case class Point(x: Double = 0.0, y: Double = 0.0) {
    def shift(deltax: Double = 0.0, deltay: Double = 0.0) = 
        copy (x + deltax, y + deltay)
}

val p1 = new Point(x = 3.3, y = 4.4)
val p2 = p1.copy(y = 6.6)

方法具有多个参数列表

示例

代码
abstract class Shape() {
    def draw(offset: Point = Point(0.0, 0.0))(f: String => Unit): Unit =
        f(s"draw(offset = $offset), ${this.toString}")
}

case class Circle(center: Point, radius: Double) extends Shape
调用有多个参数列表的draw方法
s.draw(Point(1.0, 2.0))(str => println(s"ShapesDrawingActor: $str"))
// 也可以将圆括号替换为花括号
s.draw(Point(1.0, 2.0)){str => println(s"ShapesDrawingActor: $str")}
// 或者这样
s.draw(Point(1.0, 2.0)){str =>
    println(s"ShapesDrawingActor: $str")
}
// 亦或这样
s.draw(Point(1.0, 2.0)){
    str => println(s"ShapesDrawingActor: $str")
}

优势

  • 代码更清晰
  • 在之后的参数列表中进行类型判断
  • 可以用最后一个参数列表来推断隐含参数.隐含参数是用implicit关键字声明的参数.

Future简介

  • scala.concurrent.Future是Scala提供的一个并发工具,其中的API使用隐含参数来减少冗余代码
  • 将任务封装在Future中执行时,该任务的执行是异步的

示例

代码

并发发出5个任务,并在任务结束时处理任务返回的结果.

// file: future.scala
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

def sleep(millis: Long) = {
    Thread.sleep(millis)
}

def doWork(index: Int) = {
    sleep((math.random * 1000).toLong)
    index
}

(1 to 5) foreach { index =>
    val future = Future(doWork(index))

    future onSuccess {
        case answer: Int => println(s"Success! returned: $answer")
    }
    future onFailure {
        case th: Throwable => println(s"Failure! returned: $th")
    }
}

sleep(3000)     // 等待足够长时间,确保工作进程结束
println("finito!")
运行

scala future.scala

运行结果
Success! returned: 2
Success! returned: 4
Success! returned: 1
Success! returned: 5
Success! returned: 3
finito!
说明
  • 用foreach对一个从1到5的Range进行迭代,调用了scala.concurrent.Futrue.apply, 这是单例对象Future的工厂方法.
  • Future.apply返回一个新的Future对象,然后控制权就交给循环了,该对象将在另一个线程中执行doWork(index)
  • 用onSuccess注册一个回调函数,当future成功执行完毕后,该回调函数会被执行.这个回调函数是一个偏函数.
  • Future API允许我们通过ExecutionContext来配置并发操作的执行.import scala.concurrent.ExecutionContext.Implicits.global语句导入了默认的ExecutionContext.示例中调用了3个方法,其中的这些方法的第二个参数列表具有隐含的ExecutionContext参数,由于没有指定,使用了默认的ExecutionContext.
  • 使用implicit关键字声明变量为implicit.只有被声明为implicit的函数参数才允许调用时不给出实参.

嵌套方法的定义和递归

方法的定义可以嵌套.

代码示例

代码
// file: factorial.scala
def factorial(i: Int): Long = {
    def fact(i: Int, accumulator: Int): Long = {
        if (i <= 1)
            accumulator
        else
            fact(i - 1, i * accumulator)
    }

    fact(i, 1)
}

(0 to 5) foreach ( i => println(factorial(i)) )
运行

scala factorial.scala

输出
1
1
2
6
24
120

字面量

整数字面量

  • 整数字面量可以以十进制,八进制,十六进制的形式出现
类型格式例子
十进制0或非零值,后面跟上0个活多个数字0,1,321
十六进制0x后面更上一个或多个十六进制数字(0-9,A-F,a-f)oxFF,0x1a3b
八进制0后面跟上一个或多个八进制数字(0-7)013,077

整数字面量

目标类型下限上限
Long-2^632^63-1
Int-2^312^31-1
Short-2^152^15-1
Char02^16
Byte-2^72^7-1

- 如果整数字面量的值超出了以上表格中所示的范围,将会引发一个编译错误.
- 字面量类型默认推断为Int

浮点数字面量

  • 默认推断类型为Double
示例
.14
3.14
3.14F
3.14D
3E5
3.14e-5
3.14e+5
3.14e-4D

布尔型字面量

布尔型字面量可以为truefalse

字符字面量

  • 字符字面量要么是单引号内的一个可打印的Unicode字符,要么是一个转义序列.
  • 值在0~255的Unicode字符可以用八进制数字的转义形式表示,即一个反斜杠后面跟上最多三个八进制数字字符
字符常量示例
'A'
'\u0041'
'\n'
'012'
'\t'
字符转义序列
转义序列含义
\b退格(BS)
\t水平制表符(HT)
\n换行(LF)
\f表格换行(FF)
\r回车(CR)
\”双引号(“)
单引号(‘)
反斜杠()

不可打印的Unicode字符是不允许的,如\u0009(水平制表符), 应该使用等价的转义形式\t

字符串字面量

  • 字符串字面量是被双引号和三重双引号包围的字符串序列

符号字面量

  • 符号是一些规定的字符串
  • 符号字面量是单引号后更上一个或多个数字,字母或下划线,但第一个字符不能是数字
  • 符号字面量'id是表达式scala.Symbol("id")的简写形式
  • 如果需要创建包含空格的符号,可以使用Symbol.apply, 如Symbol.apply(" Programming Scala ")

函数字面量

  • (i: Int, s: String) => s+i 是一个类型为 Function2[Int, String, String] (返回值类型为String)的函数字面量

  • 我们可以使用函数字面量来声明变量,下面两种声明是等价的:

    val f1: (Int, String) => String     = (i, s) => s+i
    val f2: Function2[Int, String, String]  = (i, s) => s+i

元组字面量

  • Scala库中包含TupleN类,如Tuple2, 用于组建N元素组
定义
val tup = ("strig", 2016)   // 定义了一个Tuple2的实例
val t1: (Int, String) = (1, "one")
val t2: Tuple2[Int, String] = (2, "two")
使用
// File: tuple.scala
val t = ("Hello", 1, 2.3)
println("print the whole tuple:" + t)
println("print the first item:" + t._1)
println("print the second item:" + t._2)
println("print the third item:" + t._3)

val (t1, t2, t3) = ("World", '!', 0x22)
println(t1 + ", " + t2 + ", " + t3)

val (t4, t5, t6) = Tuple3("World", '!', 0x22)
println(t4 + ", " + t5 + ", " + t6)
运行

scala tuple.scala

输出
print the whole tuple:(Hello,1,2.3)
print the first item:Hello
print the second item:1
print the third item:2.3
World, !, 34
World, !, 34
两元素的元组

两元素的元组有时被简称为pair.其定义方法有多种:

  • (1, "one")
  • 1 -> "one"
  • Tuple2(1, "one")

示例:

scala> val t = 1 -> "one"
t: (Int, String) = (1,one)

scala> t._1
res0: Int = 1

scala> t._2
res1: String = one

Option, Some,None: 避免使用null

  • Option有两个具体的子类,SomeNone.
  • Some表示有值
  • None表示没有值

封闭类的继承

  • Scala设计了关键字sealed,其告诉编译器所有的子类必须在同一个源文件中声明.在Scala库中,Some与None就是与Option声明在同一源文件中,这一技术有效防止了Option类派生其他子类型.
  • 如果要防止用户派生任何子类, 可以用final关键字声明

用文件和名空间组织代码

  • Scala沿用Java用包来表示命名空间的这一做法,但它更加灵活.
  • 文件名不必与类名一致
  • 包结构不一定要与目录结构一致
  • 可以定义与文件的”物理”位置独立的包结构
  • Scala不允许在脚本中定义包,脚本被隐含包装在一个对象中.在对象中声明包是不允许的
  • 不能再类或对象中定义包

导入类型及其成员

  • _被当做通配符, 因为在Scala中,*允许用作函数名

示例

Scala中导入Java类型.

import java.awt._               // 导入包内所有类型
import java.io.File             // 导入包中单独的Scala类型或Java类型
import java.io.File._           // 导入了java.io.File中所有的静态方法和属性.与之等价的Java import语句为:
                              // import static java.io.File.*
import java.util.{Map, HashMap} // 选择性导入
  • 导入是相对的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值