- 《快学 Scala》 学习笔记 - Chapter 2
- Scala学习笔记 A2/L1篇 - 特质Traits
- 《快学 Scala》 学习笔记 - Chapter 3
- 《快学 Scala》 学习笔记 - Chapter 1
- Scala学习笔记 A2/L1篇 - 集合 Collection
- Scala学习笔记 A2/L1篇 - 高阶函数 Higher-O
- Scala学习笔记 A2/L1篇 - 模式匹配和样例类 Patt
- Scala学习笔记 A2/L1篇 - XML处理 XML Pro
- Scala学习笔记 A3/L2篇 - 高级类型 Advanced
- Scala学习笔记 A3/L2篇 - 类型参数 Type Par
条件表达式
-
scala的表达式是有返回值的,和erlang一样,语句的最后一个表达式就是返回值
-
可以使用 val s = if (x>0) 1 else -1 的方式声明变量,此处s 为 Int 类型
- 也可以用 if (x>0) s=1 else s=-1 但前提是先要通过var 声明 s, 也就是说s就不能是常量了
-
val s=if(x>0) “asdfadf” else -1 的表达式中,s的类型为Any,因为两个表达式的值类型是不相同的,即混合类型,那么只能是他们的公共超类Any了
-
if (x>0) 1 则等同于 if (x>0) 1 else ()
-
() 等同于 java中的void
-
() 在scala 中的值为Unit,表示“无值”的值
-
-
scala终端里需要注意else的换行问题
if (x > 0) 1 else if ( x == 0 ) 0 else -1
需要写成
if (x > 0) { 1 } else if ( x == 0 ) 0 else -1
-
在编译器中编译时是无需顾虑这个问题的
-
可以通过:paste 模式将代码粘贴进去后统一解析执行,这样scala终端就不会近视了
-
语句终止
-
正常多行时不需要分号,单行有多个表达式时需要分号
- 但是如果不习惯不使用,则可以用,没什么坏处
-
s=s0+(v-v0)t+ // +告诉解析器这里不是语句的末尾
0.5(a-a0)tt- 这里跟GO很像,符号放到最后,而不是在新一行的开始
-
scala推荐左括号在表达式结尾,而不是新一行的开始
块表达式和赋值
-
Scala的结果也是一个表达式,和其他语言不同,{}的最后一个表达式就是这个块表达式的值,因此可以使用块表达式初始化一个值,此特性和Erlang相同
- val distance = { val dx=x0; val dy=y-y0; sqrt(dxdx+dydy**) }
-
Scala的负值动作是没有值的,严格来讲他的值是Unit
-
比如 { r=r * n; n -= 1 } 的值是 Unit
-
不要 x=y=1, 因为 y=1的值是()
-
输入和输出
-
print
-
println
-
printf
-
readInt
-
readDouble
-
readByte
-
readShort
-
readLong
-
readFloat
-
readBoolean
-
readChar
-
readLine
- readLine(“Your name:”)
循环
-
while(n>0) {}
-
for(i < -1 to n) {}
-
语法结构可以理解为: for ( i <- 表达式)
-
1 to n 代表的是1.to(n), 即生成了1 到 n的数组
-
<- 代表将后面的表达式的值逐一负值到i,但是这里取决于表达式的类型,这里是一个Range类型
-
如果期望表达式的范围是0到n-1 则可以使用 for( i <- until s.length) {}
-
for (ch <- “hello”)
- 该表达式将字符循环负值给了ch
-
-
scala没有break和continue
-
一. 使用Boolean型的控制变量
-
二. 使用嵌套函数 — 你可以从函数中return
-
三. 使用 Breaks 对象中的 break 方法
import scala.util.control.Breaks._ breakable { for (...) { if (...) break; // 退出breakable块 ... } }
-
这种实现其实是在 break 这个语句抛出了一个异常,然后 breakable 块捕获异常来实现的
-
如果对性能要求很高的,应该尽量避免使用这套机制
-
-
高级for循环和for推导式
-
通用表达式
-
for (变量1 <- 表达式1 [保护语句1]; [变量定义]…; 变量2 <- 表达式2 [保护语句2]) [yield 表达式]
-
保护语句格式: if xxxx,
-
是一个以if 开头的Boolean 表达式
-
-
for { 变量1 <- 表达式1 [保护语句1]
[变量定义]
...
变量2 <- 表达式2 [保护语句2] } [yield 表达式]- 可以使用圆括号,分号可以修改为换行
-
-
例子
for(i <- 1 to 3; j <- 1 to 3 if i != j ) print ( ... )
等同于Go语言的
for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { if i != j { fmt.Print(...) } } }
for (i <- 1 to 3; from = 4 - i; j <- from to 3) print(...)
上面在for中定义了变量
for (i <- 1 to 10) yield i % 3
yield表达式,将生成结果:Vector(1,2,0,1,2,0,1,2,0,1)
for { i <- 1 to 3 from = 4 - i j <- from to 3 }
函数
-
Scala除了方法还支持函数,方法对对象进行操作,函数不是
-
def abs(x: Double) = if ( x >= 0) x else -x
-
必须给出所有参数的类型
-
如果函数比较复杂,则可以使用代码块{}, 将代码放到代码块里即可
-
返回参数
-
如果是非递归函数
- 不需要给出返回类型,Scala编译器可以通过=符号右侧的表达式的类型推断出返回类型
-
如果是递归函数
def fac(n: Int): **Int** = if (n <=0) 1 else n * fac(n-1)
-
-
默认参数和带名参数
-
定义
-
我们在调用某些函数时并不显示的给出所有的参数值,对于这些函数我们可以使用默认参数
-
传入的参数如果不带名字,则会按顺序对应到默认参数里
-
有时候可以我们只想修改特定的默认参数,而这个参数又在其他的默认参数后面,因此我们需要使用带名参数的方法来传入值
-
-
例子
def decorate(str: String, left: String = "[", right: String = "]") = left + str + right
left参数和right参数均有默认值,在调用的时候如果无特殊需求,则不需要传入值
带名参数的调用方法def decorate("Hello", right = "]<<<")
变长参数
-
def sum(args: Int*) = {}
-
调用方法
-
val s = sum(1, 4, 9, 16)
-
val s = sum(1, 4, 9, 16, 25, 100)
-
-
-
可以传入任意数量的参数
-
错误的使用方法
-
例一
-
错误
- val s = sum(1 to 5)
-
正确
-
val s = sum(1 to 5: _*)
-
后面的 :_* 的作用类似Golang的
- sum(numbers …)
-
-
-
-
-
注意
-
当你调用变长参数且参数类型为Object的Java方法时,你需要手工对基本类型进行转换
-
例如
-
Java方法
-
MessageFormat public static String format(String pattern, Object... arguments)
- 此处为Java的方法,且变参的类型为Object
-
-
调用
-
var str = MessageFormat.format("The answer to {0} is {1}", "everything", 42.asInstanceOf[AnyRef])
-
由于42是基本类型,因此需要手动转换到 Scala 的 AnyRef 上,AnyRef 等同于 Java 的 Object
-
-
-
-
过程
-
定义
-
如果函数体包含在花括号当中,但没有前面的 = 号, 那么返回类型就是Unit,这样的函数被称为 (procedure)
-
过程不返回值,我们调用它仅仅是为了他的副作用
-
-
例子
-
我们只是想在屏幕上输出一段文字
-
def box(s: String) { … }
-
大家仔细看,这里是没有等号的,没有写成 def box(s: String) = { … }
-
-
-
习惯性问题
-
def box(s: String): Unit = { … }
-
建议大家总是显式的声明Unit返回类型
-
懒值
-
定义
- 当val被声明为lazy时,他的初始化将被推迟,直到我们首次对他取值
-
例子
lazy val words = scala.io.Source.fromFile("/usr/share/dict/words").mkString
当我们第一次访问的时候,这个文件的内容才会被读取,然后复制给 val
-
对比说明
val words = scala.io.Source.fromFile("/usr/share/dict/words").mkString //在words被定义时即被取值 lazy val words = scala.io.Source.fromFile("/usr/share/dict/words").mkString //在words被第一次使用时取值 def words = scala.io.Source.fromFile("/usr/share/dict/words").mkString //words函数每次被调用时取值
-
其他说明
- lazy 特性并不是没有额外开销,我们每次访问都会有一个方法被调用,而这个方法将会以线程安全的方式检查该值是否被初始化过
- 有点像Golang里的sync.Once
异常
-
说明
-
受检异常
-
scala中无java里的受检异常特性,即在函数定义的时候就要指出本函数将会抛出什么异常,如果代码里抛出了未在定义里事先列出的异常,则在编译时会报错
-
scala的设计者决定不支持此特性,因为在编译期间做彻底的检查也并不总是好事
-
-
-
表达式
-
throw 表达式有特殊的类型 Nothing
-
作用
-
if/else
-
if (x > 0) { sqrt (x)
} else throw new IllegalArgumentException("x should not be negative")-
当 x > 0 时返回的值是Double
-
当 x <=0 时抛出异常,既 Nothing 类型
-
因此该 if/else 表达式的类型是 Double
-
-
-
-
-
-
捕获异常
-
语法
-
try { … } catch { … }
-
try { … } finally { … }
-
作用和异常的抛出规则类似,如果finally 里出了异常,则会覆盖之前的异常
-
-
例子
try { process(new URL("http://xxxx.com/yyy.gif")) } catch { case _: MalformedURLException => println("Bad URL:" + url) case ex: IOException => ex.printStackTrace() }
-
catch 采用的是模式匹配,此例子会将抛出的异常从上到下,依次对比异常类型,如果能匹配上则执行 => 后面的语句
-
模式匹配部分类似Go的类型选择
select v:=Exception.(type) { case MalformedURLException:{ println("Bad URL:" + url) } case IOException:{ v.printStackTrace() } }
-
-
练习
-
第一题
def signum(v: Int): Int = { if(v > 0 ){ 1 } else if( v == 0 ){ 0 } else { -1 } }
-
第二题
- 是 Unit,代表空
-
第三题
-
var x=()
- scala赋值动作本身是没有值的,即赋值动作的结果为Unit,因此 x=y=1, 他的第一步动作是 y=1, 得到 Unit 类型,如果x为Int类型则会报错,因此x应该为Unit类型
-
-
第四题
for( i<-1 to 10; j=10-i+1) System.out.println(j)
-
第五题
def countdown(n: Int):Unit = { for( i<-1 to n; j=n-i+1) System.out.println(j) }
-
第六题
var value:Long = 1 for(char<- "Hello") value*=char System.out.println(value)
-
一开始做题时,书上的Hello值为 9415087488, 而我算出来是 825152896,后来发现如果 var value = 1 如果不写类型则是Int型,因此是存储不下的,要声明为Long才行
-
此处比较坑爹的是,scala 的解释器,直接带入 72101108108111 后算出来的值也是错的, 还是erlang智能
-
scala> 72101108108111
res2: Int = 825152896 -
Eshell V8.2 (abort with ^G)
1> 72101108108111.
9415087488
-
-
-
第七题
"Hello".foldLeft(1L)(_ * _.toInt)
-
第八题
def product(s: String):Long = { s.foldLeft(1L)(_ * _.toInt) }
-
第九题
def product(s: String,seq: Int = 0, value: Long = 1L):Long = { if(seq>=s.length) value else product(s, seq+1, value*s(seq)) }
-
第十题
def calc(x:Long, n:Long):Long = { if(n>0){ if(n % 2 == 0L){ var y=calc(x,n/2) y*y } else { x*calc(x,n-1) } } else if(n==0){ 1 } else{ 1/calc(x,-n) } }

网友评论