一、基础
1、数据类型:
Byte、Short、Int、Long、Flout、Double、Boolean七种数据类型,且不分基本类型和引用类型。
2、运算符:
相比java,没有++和–两种操作符。
3、方法调用:
如果没有参数,方法可以不带括号。
4、变量声明:
val a="不可变类型"
var b="可变类型"
5、语句终止与返回:
- 采用return可以提前返回循环,但是一定要设置返回值的类型。
- 不用return,代码块的最后一个语句即为返回值,例如:
val a={val x=2-1
val y=3-1
sqrt(x+y) //将最后一个返回
}
6、字符串格式化:
(1)类似于java的System.out.println(“my name is %s”,“tom”)
(2)新形势:
- s插值器
val name="James"
println(s"Hello,$name")//Hello,James 此例中,$name嵌套在一个将被s字符串插值器处理的字符串中。插值器知道在这个字符串的这个地方应该插入这个name变量的值,以使输出字符串为Hello,James。使用s插值器,在这个字符串中可以使用任何在处理范围内的名字。
- f插值器(变量类型要对应,否则会报错)
val height=1.9d
val name="James"
println(f"$name%s is $height%2.2f meters tall")//James is 1.90 meters tall
- raw插值器
scala>s"a\nb"
res0:String=
a
b 这里,s 插值器用回车代替了\n。而raw插值器却不会如此处理。
scala>raw"a\nb"
res1:String=a\nb 当不想输入\n被转换为回车的时候,raw 插值器是非常实用的。
7、for循环:
- scal的for循环没有for(int i=0;i<9;i++)形式。
- for(i<-表达式),例如for(i<- 1 to/until 10 by 2)
- 高级:for(表达式1;表达式2;表达式3 if守卫),例如for(i<- 1 to 10;i<- 10 to 1 if i != j)
8、函数:
(有些可以不指定返回类型,他会自己推测,但是递归的必须标明返回值,无返回值为Unit)
def test(a:Int,b:String):String{
b + a.toString
}
9、变长参数:
def test(a:Int,b:String*)
10、类型强转------转为该类的子类:
10.asInstanceOf
11、lazy修饰符:
该值的初始化将被推迟到第一次使用该值的时候。
二、数组、集合相关
1、数组
(1)定长数组(长度不可变,其内容可变)
val arr1: Array[Int] = new Array[Int](5) //scala的[]一般存放类型,()相当于java的{}
val arr2: Array[String] = Array("2","3")
arr1(0)=10
val value=arr2(0) //scala的()相当于java和python里的[]
val arrays: Array[Array[Nothing]] = Array.ofDim(3,4) //定义多维数组
(2)变长数组
val arr3: ArrayBuffer[Int] = new ArrayBuffer[Int]()
arr3 += (1,2,3) //在末尾添加元素
arr3 ++= arr1 //++=可以添加任何集合元素
arr3.trimEnd(5) //删除后面5个元素还有trimStart
arr3.insert(2,1,2,3) //在下标2处添加1,2,3这三个元素
arr3.remove(4,2) //在下标4处删除长度为2的元素,长度可选
val array: Array[Int] = arr3.toArray //转换成定长数组
(2)常用方法
array.max
array.sum
val filtered: Array[Int] = array.filter(_>10)
val mapd: Array[Int] = array.map(_+2)
val sorted = array.sorted //不改变原数组
array.sortWith(_ > _) //改变原数组
val str1: String = array.mkString(",") //输出数组,以什么分割
val str2: String = array.mkString("[",",","]") //输出数组,以什么开始、分割、结束
2、映射
val map1: Map[String, String] = Map("key1" -> "value1", "key2" -> "value2") //不可变映射
val map2: mutable.Map[String, String] = scala.collection.mutable.Map("key1"->"value1","key2"->"value2") //可变映射
val value: String = map1("key1")
val str: String = map2.getOrElse("key2","defaultValue")
map2("key1")="keyvalue"
map2 += ("key3" -> "value3") //在原数组的基础上添加
val map4 = map1 + ("key3" -> "value3") //不可变的新增后生成一个新映射
map2 -= "key3"
3、元组(没有其他结构新增删除等操作)
val tuple: (Int, Int, Int) = (1,2,3)
val tupleValue: Int = tuple._1
val array1 = Array(1,2,3)
val array2 = Array(4,5,6)
val array3: Array[(Int, Int)] = array1.zip(array2) //拉链函数,如果两个数组长度不等,则按最小的长度算
val map: Map[Int, Int] = array1.zip(array2).toMap //转换成映射
4、列表
(1)创建列表
val list1: List[Int] = List(2,1) //不可变数组,里面的元素不可以更改
val list2: List[Int] = 2 :: (1 :: Nil) //注意::操作符是右结合的,Nil只能放在右边
val list3 = ListBuffer(0,1) //可变数组,里面的元素可以更改
(2)常用方法
val list1 = List(0,1,2,3,4)
val list2: List[Int] = list1:+3 //往后新增
val list3: List[Int] = 3 +: list1 //往前新增
val i: Int = list1(0) //获取值
val list4: List[Int] = list1.drop(1) //删除第几个值,不是下标
val tail: List[Int] = list1.tail //返回除去第一个值的列表,类似的还有init
val take: List[Int] = list1.take(2) //返回从开头到第几个下标的列表,类似的有takeRight()
val head: Int = list1.head //返回第一个值,类似的还有last
总结:
合并两个列表:list1 ::: list2(或者list1 ++ list2)
新增: list(1,2):+3或者3+: list(1,2)
获取值:list(0) list.head和list.last list.take(2)和list.takeRigt(2)
删除:list.drop(0) list.init和list.tail list.distinct
排序:sum\max\min\sort\sortedWith\reverse
判断:isEmpty\startWith\endWith\
5、集
(1)创建Set
val set1: Set[Int] = Set(1,2,3) //不可重复的结构
val set2: scala.collection.mutable.SortedSet[Int] = scala.collection.mutable.SortedSet(1,2,3) //排序的Set
val set3: scala.collection.mutable.LinkedHashSet[Int] = scala.collection.mutable.LinkedHashSet(1,2,3) //记录插入顺序
(2)常用方法
val set1: Set[Int] = Set(1,2,3) //不可重复的结构
val set2: Set[Int] = set1 + 1 //添加/删除一个
val set3: Set[Int] = set1 ++ set2 //添加/删除多个
6、易混的新增操作
- 变长数组为+=和++=
- 可变映射为+=
- 不可变映射为+
- 集为+
7、方法总结
8、懒视图
对集合类型.view或者.view(start,until)可对集合懒操作,与变量的lazy相似。
三、类、对象、特质
(一)类
1、定义Bean
(1) 成员变量为var name=”myname”自动生成getter和setter
(2) 成员变量为val name=”myname”只生成getter
(3) 覆盖自动生成的getter和setter的方法为:
Def name=name ——gettter
Def name_=(){ } ——setter
(4)@BeanProperty var name=”myname”会生成真正的getter和setter
(5)private修饰只能在本类中调用 ———————类私有
(6)private[this]不能用 类名.属性名 的方式使用 ———————对象私有
(7)private[类名]只能在该类中使用
2、主构造器
- 主构造器执行期间会执行类内的所有语句。
class People(val name:String,var age:Int){} //自动生成val和var的两个字段
class People(name:String,age:Int){} //在使用着两个字段的时候升级为字段,没使用则不升级为字段
3、辅助构造器
- 每一个辅助构造器都以前面定义的(主/辅助)构造器开始,且每一个辅助构造器都叫this。
def this(name:String,age:Int){
this()
this.name=name
this.age=age
}
4、内部类
Outter.Inner inner=new Outter.Inner //scala
Outter outter=new Outter() //java
Outter.Inneroutter.new Inner()
(二)对象
5、单例对象(类似于java的静态类)
- 作为存放工具函数或常量的地方
- 高效的共享单个不可变实例
- 需要用单个实例来协调某个服务(参考单例模式)
- 只有在第一次被使用时才执行其构造器
6、伴生对象
-
目的:实现scala中既可以有静态方法又有普通方法的目的。
-
特点:类和伴生对象可以互相访问其私有变量。
在类中访问伴生对象需调用:伴生对象名.方法。
另:程序的入口。
7、Apply和unApply方法 -
方式:在伴生对象中定义def apply()={}
-
如果是遇到Object(参数)时,即调用的是伴生对象中的def apply()={}方法
-
如果调用Object(对象)时,则调用的时unApply方法
8、枚举类型
object ScalaMain {
object ColorEnum extends Enumeration { //要继承Enumeration
type ColorEnum=Value //声明枚举类型对外暴露的变量类型
val red=Value("red") //声明枚举类型的名称,ID从0开始依次增加
val yellow=Value(1,"yellow") //声明枚举类型的ID和名称,后面的ID从此开始依次增加
val green=Value //声明枚举类型,ID从0开始依次增加,名称为val后面的默认名称
}
def main(args: Array[String]): Unit = {
for (i <- 0 until ColorEnum.maxId) print(ColorEnum(i)) //通过调用ColorEnum(i)来取得值
}
}
(三)特质
9、类型检查和类型转换
- isInstanceOf 类型检查
- asInstanceOf 类型转换
- people.getClass==ClassOf[People] 检查是否为本类而非子类
10、抽象类、抽象方法和抽象变量
- 抽象类:Abstract修饰的类
- 抽象方法:没有方法体的方法
- 抽象变量:不初始化的变量(val的只生成getter)
11、继承层级
- 所有对应java基础类型的类继承自AnyVal
- 其他类继承自AnyRef
- AnyVal和AnyRef都继承自Any
12、 特质(用with继承)
(1)用法:
- 当做接口使用:在子类中实现其方法。
- 有具体实现方法的特质(与java不同):子类中可以覆盖也可以不覆盖。
- 特质中的成员变量:已经初始化的会变为子类的成员变量,未初始化的要初始化其成员变量。
(2)带有特质的对象:可以用val people=new People with runnable实现其特质。
(3)多重继承特质:其方法最终会实现最后继承的特质的方法。
参考:https://blog.csdn.net/qiruiduni/article/details/46726809或者《快学scala》
13、等于操作符的判断
- .eq() 是判断引用是否相等
- .equal() 是判断对象是否相等
- == 如果判断null,则调用.eq(),其他调用.equal()
14、copy方法
val person1=new Person(“chang”,24)
val person2=person1.copy(age=25)
15、样例类(即用case修饰的类)
当一个类被定义成为case类后,Scala 支持模式匹配 并会自动帮你 创建一个伴生对象并帮你实现了一系列方法。
- 实现了apply方法,意味着你不需要使用new关键字就能创建该类对象。
- 实现了unapply方法,可以通过模式匹配来获取类属性,是Scala中抽取器的实现和模式匹配的关键方法。
- 实现了类构造参数的getter方法(构造参数默认被声明为val),但是当你构造参数是声明为var类型的,它将帮你实现setter和getter方法(不建议将构造参数声明为var)。
四、高阶函数和用法
1、函数(方法)类型推断
2、闭包
定义在函数内部的另一个函数可以访问外层函数的局部变量。
function a(){
var i=0;
function b(){
alert(++i);
}
return b;
}
var c = a();
c();
即,闭包的作用就是在a执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回a所占用的资源,
因为a的内部函数b的执行需要依赖a中的变量。
由于闭包的存在使得函数a返回后,a中的i始终存在,这样每次执行c(),i都是自加1后alert出i的值。
参考:http://www.jb51.net/article/85775.htm
3、柯里化
传两个参数的函数,可以转换成只传一个参数的函数并返回一个参数的函数。
这里讲得不错:http://www.mamicode.com/info-detail-1076478.html
4、模式匹配
Str match{
Case a if XXX => 1 //if是守卫,和for循环中的一样
Case _ => 2
}
用法:
(1)匹配类型:变量a后面可以加:Int来匹配类型
(2)变量赋值:把Str的值赋给了a
(3)匹配数组元组:a可以改成Array(x,y),匹配两个值的Array
5、偏函数
就是把多个参数的函数,固定几个变量,只传递其中几个参数构成的函数。
def main(args: Array[String]) {
val date = new Date
val logWithDateBound = log(date, _ : String)
logWithDateBound("message1" )
Thread.sleep(1000)
logWithDateBound("message2" )
Thread.sleep(1000)
logWithDateBound("message3" )
}
def log(date: Date, message: String) = {
println(date + "----" + message)
}
6、隐式值和隐式转换
- 就是把不属于此类型的类转换成其他类型的,以便用其方法。
- 在转换期间,编译器是自动转换的:编译器观察出他不能用此方法,就把类型开始转换,以便能用其方法。
(1)隐式值
scala> def person(implicit name : String) = name //name为隐式参数
person: (implicit name: String)String
scala> implicit val p = "mobin" //p被称为隐式值
p: String = mobin
scala> person
res1: String = mobin
(2)隐式转换
scala> def foo(msg : String) = println(msg)
foo: (msg: String)Unit
scala> implicit def intToString(x : Int) = x.toString
intToString: (x: Int)String
scala> foo(10)
10
7、泛型
(1)泛型类:class Pair[T,S](val first : T, val second : S)
(2)泛型函数:def getMiddle[T](a : Array[T]) = a(a.length / 2) //观察以上两个的不同。
(3)类型变量界定:class Pair[T<:Comparable[T]](val first:T) //T是Comparable[T]的子类型
(4)上下文界定:class Pair[T<%Comparable[T]](val first:T) //T经过隐式转换的类型是Comparable[T]的子类型