Scala 基础编程
Scala概述
Scala用一种简洁的高级语言将面向对象
和函数式编程
结合在一起。
传统业务开发- 领域模型设计(面向对象开发);大数据开发 - 数据集计算模型-(函数式编程)。函数编程
强调的是程序对数据的运算能力。在面向对象计算数据
的时候采取代码不动,移动数据。在函数式编程计算
的时候数据不动代码动。
Scala是⼀门多范式的编程语言,同时支持面向对象和面向函数编程风格。它以一种优雅的方式解决现实问题。虽然它是强静态类型的编程语言,但是它强大的类型推断能力,使其看起来就像是⼀个动态编程语言⼀样。Scala语言最终会被翻译成Java字节码文件,可以无缝的和JVM集成,并且可以使用Scala调用java的代码库。除了Scala编程语言自身的特性以外,目前比较流行的Spark计算框架也是使用Scala语言编写。Spark 和 Scala 能够紧密集成,例如 使用Scala语言操作大数据集合的时候,用户可以像是在操作本地数据集那样简单操作Spark上的分布式数据集-RDD(这个概念是Spark 批处理的核心术语),继而简化大数据集的处理难度,简化开发步骤。
编程查询指南:https://docs.scala-lang.org/tour/tour-of-scala.html
环境配置
下载对应Scala版本:https://www.scala-lang.org/download/2.11.12.html
Windows版本安装
- 点击
scala-2.11.12.msi
双击msi文件安装 - 配置Scala的环境变量SCALA_HOME变量
SCALA_HOME=C:\Program Files (x86)\scala
PATH=C:\Program Files\Java\jdk1.8.0_161/bin;C:\Program Files (x86)\scala/bin
-
打开CMD命令窗口
C:\Users\DELL>scala Welcome to Scala 2.11.12 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_192). Type in expressions for evaluation. Or try :help. scala>
CentOS安装
-
下载
scala-2.11.12.rpm
-
安装配置Scala
[root@CentOS ~]# rpm -ivh scala-2.11.12.rpm Preparing... ########################################### [100%] 1:scala ########################################### [100%] [root@CentOS ~]# scala Welcome to Scala 2.11.12 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_192). Type in expressions for evaluation. Or try :help. scala>
IDEA集成Scala开发环境
在File>Setting>Plugins点击install plugin from disk
选项,选择 scala-intellij-bin-2018.2.11.zip
安装成功后,重启IDEA。
变量
Scala是⼀种纯粹
的面向对象编程的语言。Scala语言中没有原始数据类型,这⼀点和Java语言不同,在Scala中一切皆对象。
以下是Scala语言中常见类型和类型间的继承关系:
在Java中常见的基本类型在Scala中都被剔除了,Scala将值类型和引用类型分离。
所有的数值变量类型都是 AnyVal的子类,这些变量的值都有字面值。对于一些对象类型的变量都是 AnyRef的子类。对于 AnyRef类下的变量(除String类型),一般不允许直接赋值字面量,都需要借助new
关键字创建。
变量声明
Scala语言是一种可以做类型自动推断的强类型的编程语言。变量的类型可通过编译器在编译的时候推断出最终类型。因此Scala中声明一个变量主需要告知编译器该变量的值是常量还是变量,例如:例如声明⼀个变量使用var即可,如果声明的是一个常量使用val关键字。因此Scala中变量声明的语法如下:
var|val 变量名字[:类型]=变量值[:类型]
scala> var i:Int=1:Int
i: Int = 1
scala> var j=100:Byte
j: Byte = 100
scala> j=i
<console>:13: error: type mismatch;
found : Int
required: Byte
j=i
^
scala> var k=100
k: Int = 100
scala> k=1.0d
<console>:12: error: type mismatch;
found : Double(1.0)
required: Int
k=1.0d
^
Scala虽然可以做类型自动推断,类型一旦确定,不允许更改-强类型编程语⾔。
val
表示声明常量。
scala> val i = 123
i: Int = 123
scala> i=456
<console>:12: error: reassignment to val
i=456
总结
:所有AnyVal类型的子类在声明字面值的时候,系统一般都可以自动推断出字面量类型,所以一般情况下可以省略类型的声明。
数值转换
数据类型兼容,且由小到大
可以直接赋值。
scala> var a :Byte =100
a: Byte = 100
scala> var b:Int =12
b: Int = 12
scala> b=a
b: Int = 100
又大到小
需要强转
scala> var c:Byte =100
c: Byte = 100
scala> var d:Int =12
d: Int = 12
scala> c=d
<console>:13: error: type mismatch;
found : Int
required: Byte
c=d
scala> c=d.asInstanceOf[Byte] //强制转换
c: Byte = 12
注意
:能够实现数值转换的,要求类型必须是兼容的;
scala> var num ="123"
num: String = 123
scala> var i:Int=100
i: Int = 100
scala> i=num
<console>:13: error: type mismatch;
found : String
required: Int
i=num
^
scala> i=num.asInstanceOf[Int]
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:101)
... 32 elided
String转换为AnyVal类型
scala> var a="100.5"
a: String = 100.5
scala> var d=1.0D
d: Double = 1.0
scala> d=a.toDouble
d: Double = 100.5
数组
Scala提供了简便的声明和使用方式,例如声明一个Int类型的数组,则使用如下:
声明数组
scala> var a=Array(1,2,3,4,5)
a: Array[Int] = Array(1, 2, 3, 4, 5)
scala> var a=new Array[Int](5)
a: Array[Int] = Array(0, 0, 0, 0, 0)
获取数组的值
scala> var a=Array(1,2,3,4,5)
a: Array[Int] = Array(1, 2, 3, 4, 5)
scala> a(1)
res0: Int = 2
scala> a(0)
res1: Int = 1
scala> a(0)= -1
scala> a
res3: Array[Int] = Array(-1, 2, 3, 4, 5)
scala> a.length
res4: Int = 5
scala> a.size
res5: Int = 5
简单遍历数组
scala> for(i <- 0 until a.length ) println(a(i))
-1
2
3
4
5
scala> a.foreach(item=> println(item)) //细化的
1
2
3
4
5
元组
由若干个指定类型的元素 合变量(变量的属性不可更改),称为元组类型;
scala> var a=(1,"zhangsan",true,18)
a: (Int, String, Boolean, Int) = (1,zhangsan,true,18)
scala> a = (2,"lisi",false,19)
a: (Int, String, Boolean, Int) = (2,lisi,false,19)
元组数据访问
scala> a
res1: (Int, String, Boolean, Int) = (2,lisi,false,19)
scala> a._1
res2: Int = 2
scala> a._2 = "wangwu"
<console>:12: error: reassignment to val
a._2 = "wangwu"
^
元组中元素都是只读的,一般有值类型和String类型构成。在Scala一个Tuple最多能够有22个成员。元组中的元素都是val类型不允许修改(只读),但是元组变量可以修改
Unit类型
Scala中将void作为保留关键字,使用Unit作为void替换品,在Scala中Unit表示什么也没有的对象。因此字面值()
scala> var u=()
u: Unit = ()
分支循环
if条件分支
if(条件){
}else if(条件){ }
...
else{ }
var age=35
if(age<18){
print(s"你是少年,你的年龄:${age}")
}else if(age<30){
println(s"你是⻘年,你的年龄:${age}")
}else{
println(s"你是中年,你的年龄:${age}")
}
根据age参数计算msg的取值,可以看出在Scala语法中
if分支
可以作为变量的赋值语句。可以将分支中返回的结果作为返回值,在利用分支做赋值的时候,不可以给return关键字,系统会自动将代码块最后一行的结果作为返回值。
var message= if(age<18){
s"你是少年,你的年龄:${age}"
}else if(age<30){
s"你是⻘年,你的年龄:${age}"
}else{
s"你是中年,你的年龄:${age}"
}
println(s"最终结果:$message")
while与do-while
while(条件){
//循环体
}
在scala中while和do-while没有
continue
和break
关键字。
//while
var i=5
while (i>0){
println(s"当前i的值:${i}")
i = i-1
}
println("~~~~~~~~~~~~~~~~~")
//do-while
i=5
do{
println(s"当前i的值:${i}")
i = i-1
}while(i>0)
Breaks
Scala 语言中默认是没有break
语句,但是在 Scala 2.8 版本后可以使用另外一种方式来实现 break 语句。当在循环中使用break语句,在执行到该语句时,就会中断循环并执行循环体之后的代码块。
scala> import scala.util.control.Breaks
import scala.util.control.Breaks
scala> var a=10
a: Int = 10
scala> var break=new Breaks
break: scala.util.control.Breaks = scala.util.control.Breaks@17eeaaf
scala> break.breakable({
| do{
| print("\t"+a)
| a -= 1
| if(a<=5){
| break.break()
| }
| }while(a>0)
| })
//10 9 8 7 6
for循环-重点
- 迭代遍历数组
scala> var array=Array(1,2,3,4)
array: Array[Int] = Array(1, 2, 3, 4)
scala> for(item <- array){print(item+"\t")}
//1 2 3 4
- 通过下标遍历
scala> var array=Array(1,2,3,4)
array: Array[Int] = Array(1, 2, 3, 4)
scala> for(i <- 0 until array.length) {
| print(array(i))
| }
- for可以使用多的循环因子
for(i <- 1 to 9){
for(j <- 1 to i){
print(s"$i * $j = "+(i*j)+"\t")
if(i==j) println()
}
}
scala> for(i <- 1 to 9;j <- 1 to i){
| print(s"${i}*${j} ="+i*j+"\t")
| if(i==j){
| println()
| }
| }
1*1 =1
2*1 =2 2*2 =4
3*1 =3 3*2 =6 3*3 =9
4*1 =4 4*2 =8 4*3 =12 4*4 =16
5*1 =5 5*2 =10 5*3 =15 5*4 =20 5*5 =25
6*1 =6 6*2 =12 6*3 =18 6*4 =24 6*5 =30 6*6 =36
7*1 =7 7*2 =14 7*3 =21 7*4 =28 7*5 =35 7*6 =42 7*7 =49
8*1 =8 8*2 =16 8*3 =24 8*4 =32 8*5 =40 8*6 =48 8*7 =56 8*8 =64
9*1 =9 9*2 =18 9*3 =27 9*4 =36 9*5 =45 9*6 =54 9*7 =63 9*8 =72 9*9 =81
- for和if的使用
scala> for(i<- 0 to 10;if(i%2==0)){
| print(i+"\t")
| }
//0 2 4 6 8 10
- for和yield关键字实现元素的提取,创建子集
scala> var a=Array(1,2,3,4,5)
a: Array[Int] = Array(1, 2, 3, 4, 5)
scala> var res=for(item<-a) yield item*item
res: Array[Int] = Array(1, 4, 9, 16, 25)
match-case(模式匹配)
在Scala中剔除java中switch-case
语句,提供了match-case
替代方案,该方案不仅仅可以按照值匹配,还可以按照类型、以及值得结构(数组匹配、元组匹配、case-class匹配等.);
- 值匹配
var a=Array(1,2,3)
var i=a(new Random().nextInt(3))
var res= i match {
case 1 => "one"
case 2 => "two"
case 3 => "three"
case default => null
}
println(res)
- 类型匹配
var a=Array(100,"张三",true,new Date())
var i=a(new Random().nextInt(4))
var res= i match {
case x:Int => s"age:${x}"
case x:String => s"name:${x}"
case x:Boolean => s"sex:${x}"
case _ => "啥都不是"
}
println(res)
注意:
_
表示默认匹配等价default
关键字
函数(方法)
函数声明
def 函数名(参数:参数类型,...):[返回值类型] = {
//方法实现
}
标准函数
def sum(x:Int,y:Int):Int = {
return x+y
}
//或者
def sum02(x:Int,y:Int)= {
x+y
}
可以省略
return
关键字以及返回值类型,系统一般可以自动推断。将代码块最后一行作为返回值。
可变长参数
def sum03(values:Int*)= {
var total=0
for(i <-values){
total+=i
}
total
}
def sum04(values:Int*)= {
values.sum
}
注意:可变长参数必须放置在最后
命名参数
def sayHello(msg:String,name:String):Unit={
println(s"${msg}~ ${name}")
}
sayHello("hello","张三")
sayHello(name="张三",msg="hello")
参数默认值
def sayHello02(msg:String="哈喽",name:String):Unit={
println(s"${msg}~ ${name}")
}
def sayHello03(name:String,msg:String="哈喽"):Unit={
println(s"${msg}~ ${name}")
}
sayHello02(name="张三")
sayHello03("李四")
内嵌函数
def factorial(x:Int):Int={
def mulit(i:Int):Int={
if(i>1){
i*mulit(i-1)
}else{
1
}
}
mulit(x) //递归
}
println(factorial(5))
柯里化(Currying)
在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数的函数,并且返回接受余下的参数且返回结果的新函数的技术。
def sum02(x:Int,y:Int)= {
x+y
}
====
def sum04(x:Int)(y:Int):Int= {
x+y
}
scala> def sum04(x:Int)(y:Int):Int= {
| x+y
| }
sum04: (x: Int)(y: Int)Int
scala> sum04(1)(2)
res41: Int = 3
scala> var s=sum04(1)(_) //部分应用函数
s: Int => Int = <function1>
scala> s(2)
res47: Int = 3
scala> var s2=sum04 _ //部分应用函数
s2: Int => (Int => Int) = <function1>
scala> s2(1)
res52: Int => Int = <function1>
scala> s2(1)(2)
res53: Int = 3
匿名函数|方法
只有参数列表和返回值类型,没有方法名,通常使用匿名函数形式去声明⼀个函数式变量
;
scala> var sum=(x:Int,y:Int)=> {x+y}
sum: (Int, Int) => Int = <function2>
scala> var multi=(x:Int,y:Int)=> {x*y}
multi: (Int, Int) => Int = <function2>
scala> println(sum(1,2)+" | "+multi(1,2))
3 | 2
def
关键字可以定义一个函数式变量。也可以声明一个标准方法。
def sum(x:Int,y:Int):Int = {
return x+y
}
def sum=(x:Int,y:Int)=>x+y
var sum=(x:Int,y:Int)=>x+y
var sum:(Int,Int)=> Int = (x,y)=> x+y
var sum = ((x,y)=> x+y):(Int,Int)=> Int
通过上述变换可以推导出 函数可以转换为变量,因此可以使用var或者val修饰函数式变量,又因为函数式变量是函数,所以可以使用def修饰。
def method(op:(Int,Int)=>Int)(x:Int,y:Int)={
op(x,y)
}
val result01 = method((x,y)=>x+y)(1,2)
val result02 = method((x,y)=>x*y)(1,2)
println(result01)
println(result02)