1、语法基础
//变量
scala>var a = 100 //变量
//常量
scala>val a = 100 //常量,不能重新赋值。
//定义类型
scala>val a:String = "hello" ;
scala>a = "world" //wrong
//操作符重载 _ $
scala>1 + 2
scala>1.+(2) //和上面的效果一样
//scala函数,没有对象.
//scala方法,通过对象调用。
scala>import scala.math._ //_ ===> *
scala>min(1,2)
//以下三种操作效果一样
scala>1.toString //方法
scala>1.toString() //方法形式
scala>1 toString //运算符方式
//apply
scala>"hello".apply(1) //等价于xxx.apply()
scala>"hello"(1) //和上面的效果一样,相当于取出索引为1的字符,即e
//条件表达式,scala的表达式有值,是最后一条语句的值。
scala>val x = 1 ;
scala>val b = if (x > 0) 1 else -1 ;
//Any 是Int和String的超类。
//类型转换
scala>1.toString()
scala>"100".toInt()
//空值
scala>val y = (x = 1) //y:Unit= ()类似于java void.不推荐这样写
//粘贴复制
scala>:paste
....
ctrl + d //结束粘贴模式
//输出
scala>print("hello")
scala>println("hello") //换行输出
scala>printf("name is %s , age is %d", "tom",12); //输出字符串
//读行
scala>val password = readLine("请输入密码 : ") ;
//查看帮助
scala>:help
2、控制结构和函数
//循环
scala>:paste
var i = 0 ;
while(i < 10 ){
println(i) ;
i += 1;
}
//99表格
scala>:paste
var row = 1 ;
while(row <= 9 ){
var col = 1 ;
while(col <= row){
printf("%d x %d = %d\t",col,row,(row * col)) ;
col += 1 ;
}
println();
row += 1 ;
}
//百钱买白鸡问题.
100块钱100只鸡。
公鸡:5块/只
母鸡:3块/只
小鸡:1块/3只
//公鸡
var cock = 0 ;
while(cock <= 20){
//母鸡
var hen = 0 ;
while(hen <= 100/3){
var chicken = 0 ;
while(chicken <= 100){
var money = cock * 5 + hen * 3 + chicken / 3 ;
var mount = cock + hen + chicken ;
if(money == 100 && mount == 100){
println("cock : %d , hen : %d , chicken : %d",cock,hen,chicken) ;
}
}
}
}
//for循环
//to:[] 是一个闭合区间
scala>for (x <- 1 to 10){
println(x) ;
}
//until:[1,...10) 半闭半开区间
scala>for (x <- 1 10){
println(x) ;
}
//scala没有break continue语句。可以使用Breaks对象的break()方法。
scala>import scala.util.control.Breaks._
scala>for(x <- 1 to ) {
break() ;
print(x)
} ;
//for循环高级
//双循环,守卫条件,先执行内层循环,再执行外层循环
scala>
for(i <- 1 to 3 ; j <- 1 to 4 if i != j ) {
printf("i = %d, j = %d , res = %d ",i,j,i*j);
println()
} ;
//yield,是循环中处理每个元素,产生新集合vector
scala>for (x <- 1 to 10 ) yield x % 2 ;
//以上四种定义函数的方式
def add(a:Int,b:Int):Int = {
var c = a + b ;
return c ;
}
def add(a:Int,b:Int):Int = {
var c = a + b ;
c ;
}
scala>def add(a:Int,b:Int):Int =a + b
scala>def add(a:Int,b:Int):Int ={
a + b
}
//scala实现递归 n! = n * (n - 1)!
4! = 4 x 3!
4! = 4 x 3 x 2!
4! = 4 x 3 x 2 x 1!
//递归函数必须显式定义返回类型
scala>def fac(n:Int):Int = if(n ==1 ) 1 else n * fac(n-1) ;
//函数的默认值和命名参数
scala>def decorate(prefix:String = "[[",str:String,suffix:String = "]]") = {
prefix + str + suffix
}
scala>decorate(str="hello")
scala>decorate(str="hello",prefix="<<")
//变长参数
scala>def sum(a:Int*) = {
var s = 0 ;
for (x <- a) s += x;
s
}
scala>add(1 to 10) //wrong
scala>add(1 to 10:_*) //将1 to 10当做序列处理。
scala>def sum(args:Int*):Int = {
//args.head为第一个元素,args.tail为除了第一个元素外的所有元素
if (args.length == 0) 0 else args.head + sum(args.tail:_*)
}
//过程,没有返回值,没有=号。
scala>def out(a:Int){
println(a) ;
}
//lazy延迟计算,它不会立刻执行,只有当再次访问该变量的时候才会执行
scala>lazy val x = scala.io.Source.fromFile("d:/scala/buy.scala00").mkString()
x:<lazy>
x//这个时候才会打印
//异常
scala>
try{
"hello".toInt;
}
catch{ //交给
case _:Exception => print("xxxx") ;
case ex:java.io.IOException => print(ex)
}
//_ 的意义
1. 统配相当于*
2. 1 to 10 :_* ,转成序列
3. case _:Exception => print("xxxx") ;
3、数组相关操作
//数组(定长)
java : int[] arr = int int[4] ;
scala>var arr = new Array[Int](10); //apply(10)
scala>var arr = Array(1,2,3,4,); //推断
scala>arr(0) //按照下标访问元素
//变长数组
scala>import scala.collection.mutable.ArrayBuffer
scala>val buf = ArrayBuffer[Int](); //创建数组缓冲区对象
//+=在末尾追加元素
scala>buf += 1
//操纵集合
scala>buf ++= ...
scala>buf ++= Array(4,5,6)
//trimEnd,从末尾移除元素
scala>buf.trimStart(2)//从开始移除2个元素
scala>buf.trimEnd(2)
//insert,在0元素位置插入后续数据
scala>buf.insert(0,1,2)
//remove按照索引移除
scala>buf.remove(0)
//toArray,缓冲对象转成数组
scala>buf.toArray
//数组操作
scala>for (x <- 1 to 10 if x % 2 ==0) yield x * 2 //
//下面两句相当于上面一句
scala>var a = Array(1 to 10:_*)
scala>a.filter(_%2==0).map(_*2)//过滤器
//数组常用方法
scala>arr.sum
scala>arr.min
scala>arr.max
//排序
scala>import scala.util.Sorting._
scala>val arr = Array(1,4,3,2)
scala>quickSort(arr) //arr有序
//Array.mkString
scala>arr.mkString("<<",",",">>") //将数组按某种规则转成字符串:<<1,2,3,4>>
//多维数组
scala>var arr:Array[Int] =new Array[Int](4); //一维数组
//二维数组
scala>var arr=new Array[Array[int]](4)
//下面是赋值操作
scala>arr(0)=Array(1);
scala>arr(1)=Array(1,2);
scala>arr(2)=Array(1,2,3);
//二维数组,3行4列
scala>val arr = Array.ofDim[Int](3,4)
//下标访问数组元素
scala>arr(0)(1)//第1行第2列
scala>arr.length//数组长度
//和java对象交互,导入转换类型,使用的隐式转换
scala>import scala.collection.JavaConversions.bufferAsJavaList
scala>val buf = ArrayBuffer(1,2,3,4);
scala>val list:java.util.List[Int] = buf ;//将scala的数组缓冲区转换成java的列表
4、映射和元组
//映射和元组
//key->value
//scala.collection.immutable.Map[Int,String] =不可变集合
scala>val map = Map(100->"tom",200->"tomas",300->"tomasLee")
//通过key访问value
scala>map(100)
scala>val newmap = map + (4->"ttt")//往原来集合中添加新元素,返回newmap为(100->"tom",200->"tomas",300->"tomasLee",4->"ttt")
//原来的map不变,还为Map(100->"tom",200->"tomas",300->"tomasLee")
//可变集合
scala>val map = new scala.collection.mutable.HashMap[Int,Int]
scala>val map = scala.collection.mutable.HashMap[Int,Int]()
scala>map += (1->100,2->200) //追加
scala>map.+(5->5000,6->6000,7->7000) //这是覆盖,即覆盖原来的集合
scala>map -= 8 //移除元素
//迭代map
scala>for ((k,v)<- map) println(k + ":::" + v);
//使用yield操作进行倒排序(kv对调)
scala>for ((k,v)<- map) yield (v,k);
//元组tuple,元数最多22-->Tuple22
scala>val t = (1,"tom",12) ;//这就表示一个三元元组
//访问元组指定元
scala>t._2
scala>t _2 //和上面的一样,但不推荐使用
//直接取出元组中的各分量
scala>val (a,b,c) = t //a=1,b="tom",c=12
//数组的zip,
//西门庆 -> 潘金莲 牛郎 -> 侄女 ,
scala>val hus = Array(1,2,3);
scala>val wife = Array(4,5,6);
scala>hus.zip(wife) //(1,4),(2,5),(3,6)
5、类
scala>class Person{
//定义变量,私有类型,必须初始化
//set/get也私有
private var id = 0 ;
//只有get方法,没有set方法(因为age是常量val)
val age = 100 ;
//生成公有属性,和共有的get/set方法。(注意:name为变量var)
var name = "tom" ;
//默认public
def incre(a:Int) = {id += a ;}
//如果定义时,没有(),调用就不能加()
def current() = id
}
scala>var p = new Person();
scala>p.current()
scala>p.current
scala>p.incr(100)//此时p.current=100
scala>p.name
scala>p.name_=("kkkk")//设置属性值,相当于set方法
scala>p.name = "kkkk"//取值,相当于get方法
private[this]作用,控制成员只能在自己的对象中访问,其他对象中无法访问它
class Counter{
private[this] var value = 0 ;
def incre(n:Int){value += n}
def isLess(other:Counter) = value < other.value ;//由于前面private[this]限制了成员只能在自己的对象中访问,所以在这个位置不能访问到value(即在类内部也不行)
}
定义BeanProperty注解
class Person{
@scala.reflect.BeanProperty
var name:String = _ //_代表默认值
}
构造函数
主构造器 //
辅助构造 //
class Person{
var id = 1 ;
var name = "tom" ;
var age = 12;
//辅助构造器
def this(name:String){
this(); //调用主构造器
this.name = name ;
}
//辅助构造
def this(name:String,age:Int){
//调用前一个辅助构造器,即调用的是上面的辅助构造器
this(name) ;
this.age = age ;
}
}
//主构造,即主构造器的参数直接放置在类名之后 Person(val name:String,var age:Int , id :Int)
//val ===> 只读
//var ==> get/set
//none ==> none
class Person(val name:String,var age:Int , id :Int){
def hello() = println(id)
}
6、对象
说明:scala没有静态的概念,如果需要定义静态成员,可以通过object实现。
编译完成后,会生成对应的类,方法都是静态方法。
非静态成员对应到单例类中,单例类以Util$作为类名称。
scala>object Util{
//单例类中.(Util$)
private var brand = "benz" ;
//静态方法.
def hello() = println("hello world");
}
伴生对象(companions object)
//类名和object名称相同,而且必须在一个scala文件中定义。伴生对象可以互相访问私有属性
class Car{
def stop() = println("stop....")
}
//上面car的伴生对象
object Car{
def run() = println("run...")
}
抽象类
//定义抽象类
abstract class Dog{
def a():Unit
}
object等价于java中的静态。
object Jing8 extends Dog{
//重写方法
override def a():Unit= print("hello") ;
}
object Util{
def apply(s:String) = println(s) ;
}
Util("hello world"); //调用的是apply方法
Util.apply("hello world"); //跟上面的一样,静态方法直接调用
trait:特质,等价于java中的接口.
trait HelloService{
}
7、包和引入
//包对象:编译完之后生成以xxx为package,下面含有类package.class + package.class
package object xxxx{
}
//约束可见性,只能在该包下可用
private[package|this]
//导包
import java.io.Exception
import java.io.{A,B,C} //
import java.io.{A => A0} //别名
scalac同java一样需要先编译scala文件,产生class文件。
cmd>scalac xxxx.scala
运行class程序
cmd>scala Person
也可以一步到位:
cmd>scala Person.scala
8、继承
扩展
class Dog extends Animal{
//重写,覆盖
override def run()={...}
}
类型检查和转换
$scala>class Animal{}
$scala>class Dog extends Animal{}
$scala>val d = new Dog();
$scala>d.isInstanceOf[Animal] //true,===> instanceOf
$scala>val a = d.asInstanceOf[Animal] //强转,===> (Animal)d
//得带对象的类
$scala>d.getClass //d.getClass();
$scala>d.getClass == classOf[Dog] //精确匹配
$scala>class Animal(val name:String){}
$scala>class Dog(name:String,val age:Int) extends Animal(name){}
//抽象类
$scala>abstract class Animal(val name:String){
//抽象字段,没有初始化。
val id:Int ;
//抽象方法,没有方法体,不需要抽象关键字修饰。
def run() ;
}
9、文件和正则表达式
文件
import scala.io.Source ;
/**
* Created by Administrator on 2017/4/18.
*/
object FileDemo {
def main(args: Array[String]): Unit = {
val s = Source.fromFile("d:/hello.txt") ;
val lines = s.getLines();
for(line <- lines){
println(line)
}
}
}
//
scala.io.Source.fromFile(...).mkString()
//通过正则
val str = Source.fromFile("d:/hello.txt").mkString
val it = str.split("\\s+")
for(i <- it){
println(i)
}
10、特质
trait
//如果只有一个trait使用extends进行扩展,如果多个,使用with对剩余的trait进行扩展。
trait logger1{
def log1() = println("hello log1");
}
trait logger2{
def log2() = println("hello log2");
}
class Dog extends logger1 with logger2{}
//trait之间也存在扩展。
trait logger1{
def log1() = println("hello log1");
}
trait logger2 {
}
trait logger3 extends logger2 with logger1{
}
//with trait是需要对每个trait都是用with
class xxx extends A with T1 with T2 with ...{
...
}
//自身类型,只能混入指定类型的子类
trait logger{
this:Dog =>//即logger类只能混入Dog类的子类
def run() = println("run....")
}
trait Dog {
}
trait Jing8 extends Dog with logger{
}
11、操作符
//中置操作符
scala> 1 + 2 //
scala> 1.+(2) //
//单元操作符
scala> 1 toString //+: -:取反 !:boolean取反 ~:按位取反
//赋值操作符
$scala>+= / -= *= / /=
//:表示右结合,只有:结尾的操作符是右结合,优先级从右侧 开始
scala>val l = Nil //构造空集合.
scala>1::2::Nil //1::(2::Nil)
scala>Nil.::(2)
apply()/update()
Array(100) //Array.apply(100);
Array(100) = 200 //相当于Array.update(200)
unapply(),是apply的逆向过程
//定义类
class Fraction(val n:Int,val d:Int){
}
object Fraction{
//通过
def apply(n : Int,d:Int)= new Fraction(n,d)
//逆向过程
def unapply(f:Fraction) = Some(f.n,f.d)
}
scala>val f = Fraction(1,2) //apply(...)
scala>val Fraction(a,b) = f //unapply(...)
12、高阶函数
scala>def add(a,b) = a + b
scala>val f = add _ //将函数赋值给一个变量,函数类型变量。
scala>def multi(n:Int) = n * 2
scala>def f = multi _ //_ 表示取出函数本省
scala>Array(1,2,3,4).map(f)
//匿名函数
scala>(n:Double)=>3 * n //
scala>val f = (n:Double)=>3 * n
scala>Array(1,2,3,4).map((x) => x * 3);//(x) => x * 3是匿名函数
scala>Array(1,2,3,4).map{(x) => x * 3};//(x) => x * 3是匿名函数
//遍历数组时,输出元素值,每个元素平方返回。
f1:add
f2:sub
//
call(a:Int,b:Int,f1..,f2..){
if(a > 0) ===> add
if(a <= 0)
return f1 / f2 ;
}
//
call(1,2,fadd,sub) = 3
call(-1,2,fadd,sub) = -3
//高阶函数
def call(a:Int,b:Int,f1:(Int,Int)=>Int,f2:(Int,Int)=>Int)={
if(a > 0){
f1(a,b) ;
}
else{
f2(a,b) ;
}
}
def add(a:Int,b:Int) = a + b
def sub(a:Int,b:Int) = a- b
val f1 = add _
val f2 = sub _
call(1,2,f1,f2) //3
call(1,2,add _ ,sub _) //
call(1,2,add,sub) //
//call函数提升
call():{
if(a > 0){
f1(a,b) ;
}
else{
f2(a,b) ;
}
//y = []x
}
val f = call(1,2,f1,f2)
f(100) = 300 ;
call(1,2,add _,sub _)(100) = 300
def call(a:Int,b:Int,f1:(Int,Int)=>Int,f2:(Int,Int)=>Int)= {
var n = 0 ;
if(a > 0){
n = f1(a,b) ;
}
else{
n = f2(a,b) ;
}
//
def multi(x:Int) = x * n ;
multi _
}
//
call(1,2,(a:Int,b:Int)=>a + b , (a:Int,b:Int)=> a- b)(100)
call(1,2,(a,b)=>a + b , (a:Int,b:Int)=> a- b)(100) //这样可以
call(1,2,(a,b)=>a + b , (a,b)=> a- b)(100) //这样可以
call(1,2,a,b=>a + b , (a,b)=> a- b)(100) //wrong
//定义高阶函数
def valueAt(f:(Double)=>Double) = f(0.25)
// 参数 = 函数体(函数)
def mulby(factor : Double) = (x:Double) => x * factor
mulby(2)
//函数推断
def valueAt(f:(Double)=>Double) = f(0.25)
valueAt((x:Double)=>x * 3) //定义类型
valueAt((x)=>x * 3) //推断类型
valueAt(x=>x * 3) //省略()
valueAt(x=>x * 3) //省略()
valueAt(3 * _) //参数在右侧出现1次,就可以使用_代替。
//高级函数
scala>val arr = Array(1,2,3,4)
scala>arr.map(2 * _); //每个元素x2
scala>arr.map((e:Int)=> e * 2); //每个元素x2
scala>arr.map(_ * 2); //每个元素x2
//输出三角形
scala>(1 to 20).map("*" * _).foreach(println)
//reduceLeft,由左至右
//1,2,3 ==> (1 - 2) -3) = -4
//reduceRight,由右至左
//1,2,3 ==>1 - (2 - 3)= 2
//1,2,3,4 ==> 1 - (2 - (3 - 4)) = -2
//1,2,3,4 ==> 1 - (2 - (3 - 4)) = -2
//柯里化
scala>def mul(a:Int,b:Int) = a * b;
scala>mul(1,2)
scala>def mulone(a:Int) = {(x:Int) => a * x ;}
scala>mulone(1)(2)
//控制抽象
//定义过程,启动分线程执行block代码.
def newThread(block :()=>Unit){
new Thread(){
override def run(){
block() ;
}
}.start();
}
newThread(=>{
(1 to 10).foreach(e => {
val tname = Thread.currentThread.getName();
println(tname + " : " + e) ;
})
}
) ;
//省略()
def newThread(block: =>Unit){
new Thread(){
override def run(){
block ;
}
}.start();
}
//
newThread{
(1 to 10).foreach(e => {
val tname = Thread.currentThread.getName();
println(tname + " : " + e) ;
})
};
13、集合
//Nil
scala>1::2::Nil //Nil空集合
scala>var list = List(2,4)
scala>var l=List(2,3,4,5,6,7,8)
scala>l.head //2
scala>l.tail //List(3,4,5,6,7,8)
scala>9::list //新List(9,4,2),之前的List(4,2)仍然存在
scala>def sum(list:List[Int]):Int = {
if (list == Nil) 0 else list.head + sum(list.tail)
}
//通过模式匹配实现sum求和。
def sum(list:List[Int]):Int= list match{
case Nil => 0
case a::b=> a + sum(b) //::将列表"析构"成头部和尾部,a是list.head而b是list.tail
}
//添加删除元素操作符
scala>val set = Set(1,2,3)
scala>set + (1,2,3,5)
scala>set - (1,2,3,5)
scala>val l1 = List(1,2)
scala>val l2 = List(3,4)
scala>l1 ++ l2 //1234 ::
scala>l1 ++: l2 //1234 === :::
scala>val s1 = Set(1,2,3)
scala>val s2 = Set(2,3,4)
scala>s1 | s2 //并集
scala>s1 & s2 //交集
scala>s1 &~ s2 //差集(1,2,3) - (2,3,4) = (1)
// += 操纵的是可变集合,操纵一个元素
// ++= 操纵的是可变集合,操纵集合
// +: 操纵的是不可变集合,产生新集合
scala>import scala.collection.mutable.{Set => SSet}
scala>buf.take(2) //提取前2个元素
scala>buf.drop(2) //删除前2个元素
scala>buf.splitAt(2) //在指定位置进行切割,形成两个集合。
scala>val b1 = ArrayBuffer(1,2,3)
scala>val b2 = ArrayBuffer(3,4,5,6,)
scala>b1.zip(b2) //(1,3)(2,4)(3,5)
scala>b1.zipAll(b2,-1,-2) //(1,3)(2,4)(3,5)(-1,-2)
scala>b1.zipWithIndex() //(,0)(,1)(,2)(,3) //元素和自己的索引形成tuple.
14、模式匹配
模式匹配:类似于switch
//1.
val x = '9' ;
x match{
case '+' => print("+++")
case '-' => print("+++")
//携带守护条件
case _ if Character.isDigit(x) => print("is number!");
case _ => print("...");
}
//2.匹配类型,x类型定义成判断类型的共同超类。
val x:Any = "123";
x match{
case b:Int => print("is Int") ;
case a:String => print("is String") ;
case _ => print("is Int") ;
}
//3.匹配数组
val arr = Array(1,2)
arr match{
//匹配含有0
case Array(0) => println("有0")
//匹配是否两个元素
case Array(x,y) => println("有两个元素")
//是否从0开始
case Array(0,_*) => println("从0开始")
case _ => println("有0")
}
变量声明模式
val x = 100 ; //
val t = (1,2,3,4) ; //元组
val (a,b,c) = t //解析元组中组员.
样例类
主要用于模式匹配.
内置了apply和unapply方法,还有串行化等接口。
创建对象时不需要使用new.
abstract class Dog{}
case class Jing8(name:String) extends Dog{}
case class Shapi(age:Int) extends Dog{}
val d:Dog = new Jing8("tom");
d match{
case Jing8(name) => print("是Jing8 : " + name);
case Shapi(age) => print("是Shapi : " + age);
case _ => print("aishiuihsui");
}
密封样例类
子类和父类必须定义在同一文件中。
sealed abstract class Dog{}
case class Jing8(name:String) extends Dog{}
case class Shapi(age:Int) extends Dog{}
15、偏函数和泛型
//偏函数
val f:PartialFunction[Char,Int] = {
case '+' => 1 ;
case '-' => -1
case _ => 0
}
val x = 'a'
f(x)
//泛型
List //
Map //
//类的泛型,定义泛型类
class Pair[T,S](one:T,second:S); //定义泛型类
val p = new Pair[String,Int]("tom",12); //
val p = new Pair("tom",12); //类型推断
//方法泛型
def getMiddle[T](arr:Array[T]) = arr(arr.length / 2);
//泛型的上界,T必须是Dog的子类。
def run[T <: Dog](d:T) = println("hello")
def run2[T >: Shapi](d:T) = println("hello")
<: //上界,子类
>: //下界,父类 ???
<% // A <% B,A能够隐式转换成B
T <:Dog >:Cat //约束多个条件。
//型变
Friend[+Dog] //型变,和Dog的方向相同,即假如Dog是某个类的子类,则Friend也为其子类
Friend[-Dog] //逆变,和Dog的方向相反
16、隐式转换
隐式转换函数:使用implicit修饰的具有一个参数的函数。
//定义隐式转换函数,就近优先原则,距离它最近的函数就会用到该隐士转换函数
implicit def int2Dog(n:Int) = Shapi(n)
def run(d:Dog) = print("hello world");//所谓的隐士转换其实就是通过上面的函数将这个100转成了Shapi对象,然后再传入到这里面的
//调用隐式转换函数。
run(100) ;
//定义单例对象
object DogUtil{
//定义隐式转换函数
implicit def str2Dog(s:String) = Jing8(s) ;
}
def run3(d:Dog) = println("hello world");
//参数默认值
def decorate(prefix:String = "[[[",c:String,suffix:String="]]]") = ...
decorate(c= "hello world")
//隐式参数
object DogUtil2{
implicit val dog = Jing8("tomas") ;
}
import DogUtil2._
def run4(implicit dog:Jing8) = println("hello : ") ;
run4();