下载对应的scala版本:https://www.scala-lang.org/download/2.11.12.html
Windows版本安装:
- 点击 scala-2.11.12.msi双击msi文件安装
- 配置Scala的环境变量SCALA_HOME变量,同时在PATH变量中追加xxx;%SCALA_HOME%\bin
- 打开控制台输入scala
C:\Users\Administrator>java -version
java version "1.8.0_161"Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM)64-Bit Server VM (build 25.161-b12, mixed mode)
C:\Users\Administrator>scala
Welcome to Scala 2.11.12(Java HotSpot(TM)64-Bit Server VM, Java 1.8.0_161).
Type in expressions for evaluation. Or try:help.
CentOS安装:- 下载 scala-2.11.12.rpm
- 安装配置Scala
[root@CentOSA~]# rpm -ivh scala-2.11.12.rpm
Preparing... ########################################### [100%]1:scala ########################################### [100%][root@CentOSA~]# scala
Welcome to Scala 2.11.12(Java HotSpot(TM)64-Bit Server VM, Java 1.8.0_191).
Type in expressions for evaluation. Or try:help.
scala>
Scala 可以做变量类型自动推断。编译器在编译的时候推断出最终类型。根据字面量的值自动识别类型。
因此Scala中声明一个变量主需要告知编译器该变量的值是常量还是变量。
程序一旦编译后,类型固定,不可以更改。
声明一个变量使用 var
声明的是一个常量使用 val
语法:var|val 变量名[:类型]= 变量值[:类型] 类型可省略
var i=1 (默认Int类型)
由于编译器是可以自动推断出AnyVal类型的变量,因此用户在声明AnyVal类型的变量的时候,无需指定变量类型。
3.3 数值转换
用户可以使用asInstanceOf[类型]这种方式在数值间转换。该方式只适合类型兼容的时候使用。
scala> var i=1
i: Int =1
scala> var b:Byte=i.asInstanceOf[Byte]
b: Byte =1
scala> var b:Byte=i.toByte
b: Byte =1
如果类型不兼容可以使用toInt、toChar 方法等可以将常规参数自动转换为数值类型
scala> var sex="true"
sex: String =true
scala> sex.toBoolean
res2: Boolean =true
scala> sex.asInstanceOf[Boolean]
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Boolean
at scala.runtime.BoxesRunTime.unboxToBoolean(BoxesRunTime.java:85)...32 elided
3.4 数组
Scala提供了简便的声明和使用方式,例如声明一个Int类型的数组,
scala> val array:Array[Int]=Array(1,2,3)
scala>array(0)
res10: Int =1
可以通过length和size方法获取数组长度。
3.5 元组
元组是在Scala编程语言中的一种特殊变量。该变量可以组合任意几种类型的变量。构建一个只读的变量类型。
元组中的元素只读,其本身可以修改。
访问元组的成员可以使用_元素下标访问。
scala> var t:(String,Int)=("zs",18)
t:(String, Int)=(zs,18)
scala> t._1
res10: String = zs
scala> t._2
res11: Int =18
注意:一个元组最大允许有22个元素。
四、分支循环
4.1 条件分支-if
使用if可以作为条件分支控制语句,这一点类似与Java
var i:Int=100if(i<10){println("i小于10:"+i)}elseif(i<20){println("i小于20:"+i)}else{print(s"i大于:$i")//小s上下文取值,隐式转化。}if修饰的代码分支可以赋值给一个变量,这里的代码块中不允许使用return。
var i:Int=newRandom().nextInt(30)
var result=if(i<10){"小"}elseif(i<20){true}else{("zhangsan",1)//元组}
4.2 while/do-while
var i=5while(i !=0){
i -=1println(i)}
var i=5do{
i -=1println(i)}while(i!=0)
数组遍历:
var array=Array(1,2,3,4)for(item <- array){print(item+"\t")}
var array=Array("a","b","c")for( index <-0 to array.length-1){print(array(index))}
var array=Array("a","b","c")for( index <-0 until array.length){print(array(index)+"\t")}for循环可以使用多个循环因子:
for(i<-1 to 9;j <-1 to i){print(s"$i*$j="+(i*j)+"\t")if(i==j)println()}for循环可以嵌套if判断:
for(i<-1 to 9;if(i%2==0|| i%3==0)){print(s"$i\t")}
数组计算:
var array=0 to 9
val results =for(i <- array;if(i%2==0)) yield i*i
for(i <- results){println(i)}
模式匹配:
模式匹配是检查某个值(value)是否匹配某一个模式的机制,一个成功的匹配同时会将匹配值解构为其组成部分。
它是Java中的switch语句的升级版,同样可以用于替代一系列的 if/else 语句。
数值匹配:
val x: Int = Random.nextInt(10)
var result= x match {case0=>"zero"case1=>"one"case2=>"two"case3=>"three"case4=>"four"case _ =>"other"}println(result)
类型匹配:
var array=Array("zs",true,newDate(),1000.0)
var x=array(newRandom().nextInt(array.length))println("x:"+x)
var result= x match {case v:String =>"name"case v:Boolean =>"sex"case x:Date =>"birth"case x:Double =>"salary"case _ =>"未知"}println(result)
在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数的函数,
并且返回接受余下的参数的新函数的这种技术。(改写的_必须为最后一个参数)
def sum1(x:Int)(y:Int)(z:Int):Int={
x+y+z
}
scala>sum1(1)(2)(_)
res19: Int => Int =<function1>
scala>res19(3)
res20: Int =6
5.6 匿名函数
Scala 中定义匿名函数的语法.
箭头左边是参数列表,右边是函数体。
scala>(x:Int,y:Int)=>{x+y}
res21:(Int, Int)=> Int =<function2>
scala>res21(1,2)
res22: Int =3
注意:任意一个函数本质,就是一个变量。
var f:(Int,Int)=>Int =(x:Int,y:Int)=>{x+y}
var f:(Int,Int)=>Int =(x,y)=>{x+y}
六、Class & object
6.1 单例类
由于Scala没有静态方法和静态类,所有通过object去定义静态方法或者静态对象。- 单例对象(类似java中的工具类 )
object User {
def sayHello:(String)=>String =(name)=>"Hello ~"+name
def sayHello1(name:String):String={"Hello ~"+name
}}
var u1=User
var u2=User
println(u1 == u2)// true
6.2 伴生对象
当object和Class放在一个文件中时候,且名字保持一致称该object为当前Class的伴生对象。
classAnimal{}
object Animal{}
在同一个scala文件中定义一个类,同时定义一个同名的object,那么它们就是伴生类和伴生对象的关系,可以互相直接访问私有的field。
scala里面没有 static 关键字。那么如果想实现static的效果要怎么做呢? ==》 可以使用伴生对象
在同一个scala文件中定义一个类,同时定义一个同名的object,那么它们就是伴生类和伴生对象的关系,可以互相直接访问私有的field。
伴生对象通常会使用apply函数定义伴生类的构造方法。 这样在创建伴生类的对象时就可以省略 new 关键字。
classCat(val name:String,val age:Int){
def sayHello =println(s"hi,${name},I guess you are ${age} years old,and you have ${Cat.clawNum} claws.")}//定义一个猫的object,名字和猫咪类的类名必须完全一致。
object Cat{//object的私有field,描述爪子的数量。private val clawNum =4// val clawNum = 4// private[this] val clawNum = 4 //伴生类也不能够直接访问// def sayHello = println(s"animals usually have ${clawNum} clows.")
def apply(name: String, age: Int): Cat =newCat(name, age)
def apply(name: String): Cat =newCat(name,0)//Cat.sayHi的方式调用
def sayHi =println("a cat says hi~.")}
object里面的属性和方法就可以看作是带有static标识的。所以object中定义的方法 sayHi 不用使用类的实例调用,只能用静态的方式调用。
测试代码如下:
scala> val cat =Cat("mow",2)
cat: Cat = Cat@5fd9b663
scala> cat.sayHello
hi,mow,I guess you are 2 years old,and you have 4 claws.
scala> cat.sayHi
<console>:17: error: value sayHi is not a member of Cat
cat.sayHi
^
scala> Cat.sayHi
a cat says hi~.
上面的代码如果类比成 java ,是下面这种形式和效果:
publicclassCat{privatestaticint clawNum =4;private String name;privateint age;publicCat(String name,int age){this.name = name;this.age = age;}publicvoidsayHello(){
System.out.println("hi,"+ name +",I guess you are "+ age +" years old,and you have "+ clawNum +" claws.");}publicstaticvoidsayHi(){
System.out.println("a cat says hi~.");}publicstaticvoidmain(String[] args){
Cat cat =newCat("mimi",1);
cat.sayHello();
Cat.sayHi();}}
还要注意的是,如果object里面的属性被修饰成private[this],那么伴生类也将无法直接访问此属性。
private[this]是scala中最高级别的私有属性,只有当前object内部可以访问。
classBird(name:String)extendsAnimal(name:String) with Flyable with Speakable {
override def sleep(): String ={
s"$name 睡觉"}
override def fly(): Unit ={println(s"$name 会飞!")}
override def speek(): Unit ={println(s"$name 唧唧咋咋!")}}
classDog(name:String)extendsAnimal(name:String) with Speakable {
override def sleep(): String ={
s"$name 睡觉!"}
override def speek(): Unit ={println(s"$name 旺旺叫!")}}
var d:Animal=newDog("小黑")
var b:Animal=newBird("小麻雀")
var d2:Dog=d.asInstanceOf[Dog]
d2.speek()
6.8 动态植入
一个类通过 实现某接口 动态的给某个类新增方法。
classSmallBird(var name:String)extendsAnimal(name:String) with Speakable {
override def sleep(): String ={
s"$name 会睡觉!"}
override def speek(): Unit ={println(s"$name 咿咿呀呀!")}
override def eat(): Unit ={println(s"$name 吃鱼!")}}
①在覆盖有实现的方法必须添加overwrite;
②一个类只能继承一个类(抽象)with多个trait例如:
classAextendsB with C with D{}// B既可以是Trait也可以是Class,但是C/D必须是Trait
var sb=newSmallBird("丑小鸭") with Flyable{
override def fly(): Unit ={println(s"$name 会飞!")}}
sb.fly()
6.9 self
注意:self => 必须放在所有的属性之前
self 可以当做是this的别名
classUser(var name:String){
self =>
def setName(name:String):Unit={
self.name=name
}
def getName():String={
self.name
}}
object SelfCase {
self =>
val num =5
def main(args: Array[String]): Unit ={println(this.num)//打印结果:5println(self.num)//打印结果:5}}
classUser(val name: String)
trait Tweeter{this: User =>//这个表示 Tweeter 本身也必须是一个 User,它的子类型必须想办法符合这一要求
def tweet(tweetText: String)={println(s"$name: $tweetText")}}classVerifiedTweeter(val username: String)extendsUser(username) with Tweeter {//Tweeter 要求这个类必须是一个 User, 所以需要继承自 User 类}
val v =newVerifiedTweeter("Yanbin")
v.tweet("Hello")
6.10 Case class样列类
caseclass就像常规类,caseclass适用于对不可变数据进行建模。
与普通的class不同的是,CaseClass创建的对象 == 比较的是对象的内容。
通常用于只读数据的建模。可以简单的使用copy来实现两个对象间的值得传递
当一个类被定义成为case类后,Scala会自动帮你创建一个伴生对象并帮你实现了apply, unapply,setter, getter 和toString,equals,copy和hashCode等方法
caseclassUser(name:String,age:Int)
var u1=User("zs",19)
var u2=User("zs",19)println(u1==u2)//true
var u1=newUser("zs",19)
var u2=newUser("zs",19)println(u1==u2)//true
var u1=User("zs",19)
var u2= u1.copy(u1.name,20)println(u2)
注意:可见性使用
class 或 trait 关键字之前,
val 或 var 关键字之前 ,
def 关键字之前。如果不指定默认都是public。
7.1 public
Scala 中的默认可见性为 public,默认可见性为 public.
这是逻辑上的,实际上 Scala 中并没有 public 这个关键字,如果你用 public 来声明一个类或成员,编译器会报错
publicclassUser{//编译器不通过
var id=1
var name="zhanngsan"
var age=18
var birthDay =newDate()}
7.2 Private
1.修饰类:
只能被同包下的子类继承(同包可见),并且同包继承的类也必须是private修饰。
不同包类不可见。因为这样才不会改变原始父类的可见性。
被private修饰的类只能在同包下可用
package com.sxxd.demo08
import java.util.Date
privateclassUser{//父类
var id=1
var name="zhanngsan"
var age=18
var birthDay =newDate()}package com.sxxd.demo08
privateclassSmallUserextendsUser{//子类继承,同包可见}2.修饰属性|方法:
表示该属性/方法只能被本类|伴生对象可见,其他均不可见
package com.sxxd.demo08
import java.util.Date
privateclassUser{private var id=1
var name="zhanngsan"
var age=18
var birthDay =newDate()private def eat():Unit={println("吃!")}}
object User{
def main(args: Array[String]): Unit ={
val user =newUser()
user.eat()
user.id=2}}
7.3 Protected
1、修饰类:类可以被同包下的其他类访问。或者是同包子类使用。
package com.sxxd.demo09
protectedclassUser{}package com.sxxd.demo09
classSmallUserextendsUser{}2、修饰属性和方法
只能在本类或者本类的子类以及半生对象中访问
package com.sxxd.demo09
protectedclassUser{protected var name:String= _
protected def eat():Unit={println("eat")}}package com.sxxd.demo09
classSmallUserextendsUser{}
object SmallUser{
def main(args: Array[String]): Unit ={
val sm =newSmallUser()
sm.eat()}}
7.4 this限定
可以去除伴生对象的可见性:
classStudent(name:String){
var id=1protected|private[this] var sex=true
def sayHello():Unit={println(this.name)}}
object Student{
def apply(name: String): Student =newStudent(name)}
7.5 package限定
表示当前的类、属性、方法可以在指定的包下可见
classStudent(name:String){
var id=1private[demo01] var sex=true//01包可见
def sayHello():Unit={println(this.name)}}
object Student{
def apply(name: String): Student =newStudent(name)}
使用implicitly[类型],必须保证当前上下文有且仅有一个隐式值类型,一般这种隐式值变量的声明写在object单例类或者伴生对象中。
object MyImplicits {
implicit val i:Int=2//用作隐式值注入
implicit val s:String="Hello"//用作隐式值注入}
主函数中使用:
object testImplicits {
def main(args: Array[String]): Unit ={import com.sxxd.demo12.MyImplicits._
val b=implicitly[Int]//当前类文件中,只能有一个隐式值类型
val ss=implicitly[String]//当前类文件中,只能有一个隐式值类型println("b:"+b+"\tss:"+ss)}}
3.2 隐式注入值
要求隐式注入的值一般都会写成柯理化形式并且保证需要隐式注入的值写在最后。
object Myimplicit {
implicit val s: String ="Hello"//用作隐式值注入}
object testImplicit2 {
def main(args: Array[String]): Unit ={import com.sxxd.demo15_Exception.Myimplicit._
sayholle("zhangsan")sayholle("zhangsan")("不好")sayholle2("buhao","lisi")sayholle2(implicitly[String],"zhansgan")}//柯里化写法
def sayholle(name:String)(implicit msg:String): Unit ={println(name +"&"+msg)}//当implicit放置在参数上时候,只能放在第一参数上。
def sayholle2(implicit msg:String,name:String): Unit ={println(name +"&"+msg)}}
consol:
zhangsan&Hello
zhangsan&不好
lisi&buhao
zhansgan&Hello
3.3 隐式参数转换
该方式是通过隐式转换将参数不满足的类型转为所需类型,Scala在编译代码的时候,先尝试正常编译
如果发现编译类型不匹配,会尝试加载当前上下文中是否存在该类型和目标类型的一种隐式
转换(这种转换严格意义上应该必须唯一,否则编译器会提示错误警告,并不影响执行),如果存在则编译通过.
object MyImplicits {
implicit def str2Date(s:String):Date={
val sdf =newSimpleDateFormat("yyyy-MM-dd HH:mm:ss")
sdf.parse(s)}}
object testImplicit2 {
def main(args: Array[String]): Unit ={import com.sxxd.demo15_Exception.Myimplicit._
def tellTime(date: Date): Unit ={println(date.toLocaleString)}tellTime(newDate())tellTime("2019-06-26 10:43:00")}}
表示上下文中必须存在这种隐式值A[T]隐式值,否则程序编译出错.
这样可以在上下文中还没有隐式值得时候确保方法能编译成功。
classUser[T]{
def sayHello(t:T): Unit ={println(t)}}
object MyPrrdefs {
implicit val u1 =newUser[Int]()}
object TestFanxing {
def main(args: Array[String]): Unit ={import com.baizhi.demo17.MyPrrdefs._
sayInfomation(21)}
def sayInfomation[T:User](msg:T)(implicit u:User[T]):Unit={
u.sayHello(msg)}}
12.5 +A协变
classCovariant[+T](t:T){}//小给大
val c1 =newCovariant[Dog](newDog("小狗"))
val c2 =newCovariant[SmallDog](newSmallDog("小狗",true))
var c3:Covariant[Animal]= c1 //狗赋值给Animal
var c4:Covariant[Animal]= c2
12.6 -A逆变
classCovariant[-T](t:T){}//大的赋值给小的
val c1 =newCovariant[Dog](newDog("小狗"))
val c2 =newCovariant[SmallDog](newSmallDog("小狗",true))
var c3:Covariant[SmallDog]= c1
var c4:Covariant[Dog]= c2 //error
12.7 A不变
classCovariant[T](t:T){}//强制
val c1 =newCovariant[Dog](newDog("小狗"))
val c2 =newCovariant[SmallDog](newSmallDog("小狗",true))
var c3:Covariant[SmallDog]= c1//error
var c4:Covariant[Dog]= c2 //error
var c5:Covariant[Dog]= c1
var c6:Covariant[SmallDog]= c2