Scala学习002
闭包
通常是一个函数,返回值依赖于声明在函数外部的一个或多个变量
闭包通常来讲可以简单的认为是可以访问一个函数里面局部变量的另外一个函数
//匿名的函数,函数体内有一个变量 i,它作为函数的一个参数。
val multiplier = (i:Int) => i * 10
//multiplier 中有两个变量:i 和 factor。其中的一个 i 是函数的形式参数
//multiplier 函数被调用时,i 被赋予一个新的值。然而,factor不是形式参数,而是自由变量
var factor = 3
val multiplier = (i:Int) => i * factor
//函数变量 multiplier 成为一个"闭包",因为它引用到函数外面定义的变量,定义这个函数的过程
是将这个自由变量捕获而构成一个封闭的函数。
object Test {
def main(args: Array[String]) {
println( "muliplier(1) value = " + multiplier(1) )
println( "muliplier(2) value = " + multiplier(2) )
}
var factor = 3
val multiplier = (i:Int) => i * factor
}
字符串
在Scala中,字符串的实际是Java String,它本身是没有String类的
在Scala中,String是一个不可变的对象,所以该对象不可被更改。这就意味着你如果修改字符串就会产生一个新的字符串对象。在Scala中可以使用String Builder类创建一个可以修改的字符串
//创建字符串
var str1 = "Hello World!";
var str2:String = "Hello World!";
//创建可变字符串
val buf = new StringBuilder;
buf += 'a'
buf ++= "bcdef"
println( "buf is : " + buf.toString );
数组
Scala 语言中提供的数组是用来存储固定大小的同类型元素,数组对于每一门编辑应语言来说都是重要的数据结构之一。
数组的第一个元素索引为0,最后一个元素的索引为元素总数减1。
创建数组的两种方式
/**
* 创建数组两种方式:
* 1.new Array[String](3)
* 2.直接Array
*/
//创建类型为Int 长度为3的数组
val arr1 = new Array[Int](3)
arr1(0) = 100
arr1(1) = 200
arr1(2) = 300
//创建String 类型的数组,直接赋值
val arr2 = Array[String]("s100","s200","s300")
数组遍历的两种方式
/**
* 遍历两种方式
*/
for(i <- arr1){
println(i)
}
arr1.foreach(i => {
println(i)
})
for(s <- arr2){
println(s)
}
arr2.foreach {
x => println(x)
}
//最简单写法
arr2.foreach(println)
创建二维数组
/**
* 创建二维数组和遍历
*/
val arr3 = new Array[Array[String]](3)
arr3(0)=Array("1","2","3")
arr3(1)=Array("4","5","6")
arr3(2)=Array("7","8","9")
for(i <- 0 until arr3.length){
for(j <- 0 until arr3(i).length){
print(arr3(i)(j)+" ")
}
println()
}
可变长度数组
//需要引入相应包,mutable就是可变,immutable就是不可变
import scala.collection.mutable.ArrayBuffer
val arr = ArrayBuffer[String]("a","b","c")
arr.append("hello","scala")//添加多个元素
arr.+=("end")//在最后追加元素
arr.+=:("start")//在开头添加元素
arr.foreach(println)
trait
Scala 中 Trait (特征) 相当于 Java 的接口,实际上它比接口还功能强大。
与接口不同的是,它还可以定义属性和方法的实现。
一般情况下Scala的类可以继承多个 Trait ,从结果来看就是实现了多重继承。 Trait (特征) 定义
的方式与类类似,但它使用的关键字是 trait 。
高阶函数
高阶函数(Higher-Order Function)就是操作其他函数的函数。
Scala 中允许使用高阶函数, 高阶函数可以使用其他函数作为参数,或者使用函数作为输出结果。
函数的参数是函数
函数的返回是函数
函数的参数和函数的返回是函数
偏应用函数
Scala 偏应用函数是一种表达式,你不需要提供函数需要的所有参数,只需要提供部分,或不提供
所需参数。
例如:一个参数是完全相同,另一个参数不同,在这样一个情况之下,我们可以使用偏应用函数来
进行优化。
/**
* 偏应用函数
*/
def log(date :Date, s :String)= {
println("date is "+ date +",log is "+ s)
}
val date = new Date()
log(date ,"log1")
log(date ,"log2")
log(date ,"log3")
//想要调用log,以上变化的是第二个参数,可以用偏应用函数处理
val logWithDate = log(date,_:String)
logWithDate("log1")
logWithDate("log2")
logWithDate("log3")
默认参数值
Scala 可以为函数参数指定默认参数值,使用了默认参数
调用函数的过程中如果没有传递参数,函数就会调用它的默认参数值,
调用函数的过程中如果传递了参数,则传递值会取代默认值。
匿名函数
Scala 中定义匿名函数的语法很简单,箭头左边是参数列表,右边是函数体。
1. 有参匿名函数
2. 无参匿名函数
3. 有返回值的匿名函数
可以将匿名函数返回给val定义的值
匿名函数不能显式声明函数的返回类型
嵌套函数
可以在 Scala 函数内定义函数,定义在函数内的函数称之为局部函数。
递归函数
自己调用自己。还要有程序的出口
/**
* 递归函数 10的阶乘
*
*/
object Test {
def main(args: Array[String]) {
for (i <- 1 to 10)
println(i + " 的阶乘为: = " + factorial(i) )
}
def factorial(n: BigInt): BigInt = {
if (n <= 1)
1
else
n * factorial(n - 1)
}
}
Scala函数深化
指定参数名
一般情况下函数调用参数,就按照函数定义时的参数顺序一个个传递。但是我们也可以通过指定函
数参数名,并且不需要按照顺序向函数传递参数-
object Test {
def main(args: Array[String]) {
printInt(b=5, a=7);
}
def printInt( a:Int, b:Int ) = {
println("Value of a : " + a );
println("Value of b : " + b );
}
}
可变参数
Scala 允许你指明函数的最后一个参数可以是重复的,即我们不需要指定函数参数的个数,可以向
函数传入可变长度参数列表。
Scala 通过在参数的类型之后放一个星号来设置可变参数(可重复的参数)。
Scala参数传递
Scala的解释器在解析函数参数(function arguments)时有两种方式:
传值调用(call-by-value):先计算参数表达式的值,再应用到函数内部;
Call-by-Value 避免了参数的重复求值,效率相对较高
传名调用(call-by-name):将未计算的参数表达式直接应用到函数内部
Call-by-Name 避免了在函数调用时刻的参数求值,而将求值推延至实际调用点,但有可
能造成重复的表达式求值。
def main(args: Array[String]) {
methodA(method01())
println("**********************")
methodB(method01())
}
def method01() = {
println("Method01----")
Math.random();
}
def methodA(num: => Double) = {
println("methodA----")
println("methodA----" + num)
println("methodA----" + num)
}
def methodB(num: Double) = {
println("methodB----")
println("methodB----" + num)
println("methodB----" + num)
}
作用域保护
Scala中,访问修饰符可以通过使用限定词强调。
private[x]
protected[x]
这里的x指代某个所属的包、类或单例对象。
如果写成private[x],读作"这个成员除了对[…]中的类或[…]中的包中的类及它们的伴生对像可见外,
对其它所有类都是private。
特殊符号的应用场景
(=>)
表示函数的返回类型(Function Type)
当函数只有一个参数的时候,函数类型里面括起来函数参数的括号是可以省略的。
匿名函数
匿名函数定义, 左边是参数 右边是函数实现体
var function0 = () => Math.random()
var function1 = (x: Int) => Math.random()
case语句
val x = 10;
val y = 20;
val max = x > y match {
case true => x
case false => y
By-Name Parameters(传名参数)
传名参数在函数调用前表达式不会被求值,而是会被包裹成一个匿名函数作为函数参数传递下去
下划线
作为通配符,类似Java中的*. 如 import scala.math._
:_*作为一个整体,告诉编译器你希望将某个参数当做参数序列处理
//将 1 to 5 当做参数序列处理
val s = sum(1 to 5:_*)
private
用 private 关键字修饰,带有此标记的成员仅在包含了成员定义的类或对象内部可见,同样的规则
还适用内部类。
(new Inner).f( ) 访问不合法是因为 f 在 Inner 中被声明为 private,而访问不在类 Inner 之内。
但在 InnerMost 里访问 f 就没有问题的,因为这个访问包含在 Inner 类之内。
Java中允许这两种访问,因为它允许外部类访问内部类的私有成员。
如果字段是私有的,则getter和setter方法也是私有的
如果字段是val,则只有getter方法被生成
如果你不需要任何getter或setter,可以将字段声明为 private[this]
class Outer{
class Inner{
private def f(){println("f")}
class InnerMost{
f() // 正确
}
}
(new Inner).f() //错误
}
public
Scala 中,如果没有指定任何的修饰符,则默认为 public。这样的成员在任何地方都可以被访问。
class Outer {
class Inner {
def f() { println("f") }
class InnerMost {
f() // 正确
}
}
(new Inner).f() // 正确因为 f() 是 public
}
trait中带属性带方法实现
继承的多个trait中如果有同名的方法和属性,必须要在类中使用 override 重新定义。trait 中不可以传参数
继承
Scala 使用 extends 关键字来继承一个类。Scala 只允许继承一个父类。
重写一个非抽象方法必须使用override修饰符。
只有主构造函数才可以往基类的构造函数里写参数。
在子类中重写超类的抽象方法时,你不需要使用override关键字。
类和构造器
构造器
每个类都有有个主要的构造器,这个构造器不是单独声明的构造函数,而是和类定义交织在一起的。每当你阅读一个Scala类的时候,你就需要将他们分开理解,一个是类的定义,一个数构造函数的定义
除了主构造器之外,类还可以有人一多的辅助构造器。辅助构造器的名称为this。每一个辅助构造器都必须以一个对先前已经定义的其他辅助构造器或主构造器的调用开始
属性
类的所有属性默认都会被私有化,但是会生成getter和setter方法
如果属性用private修饰,生成getter和setter方法也是私有的
类的属性如果用val修饰,默认拥有getter方法
可以使用@BooleanBeanProperty注解增加Java方式的getter和setter
嵌套类
在Scala中,你几乎可以在任何语法结构中内嵌任何语法结构。你可以在函数中定义函数,在类中
定义类。
在Scala中,每个实例都有它自己的Member类,就和它们有自己的members字段一样
要构建一个新的内部对象,你只需要简单的new这个类名:new chatter.Member。
伴生类和伴生对象
Object
在 Scala 中,是没有 static 这个东西的,但是它也为我们提供了单例模式的实现方法,那就是
使用关键字 object。
Scala 中使用单例模式时,除了定义的类之外,还要定义一个同名的 object 对象,它和类的
区别是,object对象不能带参数。
当单例对象与某个类共享同一个名称时,他被称作是这个类的伴生对象:companion
object。
在同一个源文件里定义类和它的伴生对象。类被称为是这个单例对象的伴生类:companion
class。
类和它的伴生对象可以互相访问其私有成员。
使用 object 时,不用 new ,使用 class 时要 new ,并且 new 的时候, class 中除了方法
不执行,其他都执行。