快学scala学习笔记
var和val的区别
val和var的区别
- 内容是否不变
- val修饰的变量在编译后,等同于加上final
- 是否可以有lazy修饰.val修饰的变量还可以用lazy修饰
只有val修饰的变量才能被lazy修饰;使用lazy定义变量后,只有在调用该变量时才会实例化这个变量的值。而且惰性变量只能是不可变变量;
类似方法,先声明,后调用
scala> val a = 10
a: Int = 10
scala> lazy val b = 100
b: Int = <lazy>
scala> b
res2: Int = 100
scala> var c = 10
c: Int = 10
scala> lazy var d = 100
<console>:1: error: lazy not allowed here. Only vals can be lazy
lazy var d = 100
^
scala> def e = 1000
e: Int
scala> e
res3: Int = 1000
使用var 声明一个变量。
- var修饰的变量,内容和引用都可变
使用val声明一个常量或值
-
val修饰的变量是不可变的,注意不可变的不是内容,而是引用;
(扩展一下什么是值类型,什么是引用类型,可以使用数组举例,引用不可变,变的是内容。)
/**可变和不可变? 可变和不可变,指的是变量本身存的内容,值类型变量存的是数据本身,而引用类型变量存的是数据的引用, 值类型和引用类型? 值类型与引用类型区别: 存储方式:直接存储数据本身 vs 存储的是数据的引用,数据存储在数据堆中 内存分配:分配在栈中 vs 分配在堆中 效率:效率高,不需要地址转换 vs 效率较低,需要进行地址转换 内存回收: 使用完后立即回收 vs 使用完后不立即回收,而是交给GC处理回收 */ scala> val arr = Array(1,2,3,4,5) arr: Array[Int] = Array(1, 2, 3, 4, 5) scala> arr = Array(1,2,3) <console>:8: error: reassignment to val arr = Array(1,2,3) scala> arr(0)=10 scala> arr res1: Array[Int] = Array(10, 2, 3, 4, 5)
**使用val 还是var **
官方推荐val
使用val的好处:
- 更安全
- 代码可读性更高
- 资源回收更快,方法执行完,val所定义的变量即回收
for循环
如果for循环的循环体以yield开始,则该循环会构造出一个集合,每次迭代生成集合中的一个值
for (i <- 1 to 10) yield i % 3
//将交出Vector(1,2,0,1,2,0,1,2,0,1)
这类循环叫做for推导式(for comprehension)
生成的集合与它的第一个生成器是类型兼容的。
for (c <- "Hello"; i <- 0 to 1) yield (c+i).toChar
//将交出 "HIeflmlmop" 这里的结果是和"Hello"类型兼容的
for (i <- 0 to 1; c <- "Hello") yield (c+i).toChar
//将交出Vector('H','e','l','l','o','I','f','m','m','p') 这里的内容是和 0 to 1 类型兼容的
scala中的数据类型

Unit是值类型,他只有一个实例对象()。
Nothing是所有类型的子类,他没有一个具体的实例对象,一个常见的应用如:抛出异常、程序exit,无限循环等。
Nothing是所有类型的子类,也是Null的子类。Nothing没有对象,但是可以用来定义类型。例如,如果一个方法抛出异常,则异常的返回值类型就是Nothing(虽然不会返回) 。
def get(index:Int):Int = {
if(x < 0) throw new Exception(...)
else ....
}
if语句是表达式,有返回值,必然有返回值类型,如果x < 0,抛出异常,返回值的类型为Nothing,Nothing也是Int的子类,所以,if表达式的返回类型为Int,get方法的返回值类型也为Int。
break和continue
Scala里面没有break和continue关键字,推荐使用函数式的风格解决break和continue的功能
//需要导入包
import util.control.Breaks._
//break例子
object scalaTest {
def main(args: Array[String]): Unit = {
//break例子
breakable(
for(i<-0 until 10) {
if(i==5){
break()
}
println(i)
}
)
}
}
//continue例子
import util.control.Breaks._
object scalaTest {
def main(args: Array[String]): Unit = {
//break例子
for(i<-0 until 10) {
breakable{
if(i==5){
break()
}
println(i)
}
}
}
}
方法和函数
定义方法
定义方法的基本格式是:
def 方法名称(参数列表):返回值类型 = 方法体
def add(x: Int, y: Int): Int = x + y
println(add(1, 2)) // 3
//也可以定义成
//def add(x: Int, y: Int) = x + y
//或者
//def add(x: Int, y: Int){x + y},没有返回值,一定要用大括号把方法体括起来
带有多参数列表的方法:
def addThenMultiply(x: Int, y: Int)(multiplier: Int): Int = (x + y) * multiplier
println(addThenMultiply(1, 2)(3)) // 9
定义函数
给方法传递一个函数类型的参数:
def foo(f: Int => String) = ...
def bar(f: (Boolean, Double) => List[String]) = ...
函数可以看做是带有参数的表达式。
1,函数的定义方式:
val f1 = ((a: Int, b: Int) => a + b)
val f2 = (a: Int, b: Int) => a + b
val f3 = (_: Int) + (_: Int)
val f4: (Int, Int) => Int = (_ + _)
2,函数的定义方式:
val f1:((Int,Int)=>Int)={(x,y)=>x+y}
val f2:(Int,Int)=>Int =(x,y)=>x+y
方法和函数的区别
-
方法和函数的定义语法不同
def 方法名(参数列表):返回类型=方法体
val 变量 = (函数参数列表)=> 函数体
-
方法一般定义在某个类、特质、或者object中
-
方法可以共享使用所在类内的属性
-
Methods of an object can be passed as functions
-
Methods and functions are not the same thing
在函数式编程语言中,函数是“头等公民”,可以调用它,也可以传递它,存放在变量中,或者作为参数传递给另一个函数。
案例:首先定义一个方法,再定义一个函数,然后将函数传递到方法里面

方法转换成函数
把方法作为参数传给另一个方法或者函数的时候,方法被转化成函数
使用神奇的下划线_