@[TOC]
提示:代码实例重点在于讲解知识点上,代码相对简单,部分代码使用scala shell来直接操作的
简介
Scala是一门多范式的编程语言,一种类似java的编程语言,是可扩展语言,并集成面向对象编程和函数式编程的各种特性的混合功能编程语言。 Scala被编译后在Java虚拟机上运行。
1、 scala中声明变量
val/var 变量名称:变量类型 = 初始值
val定义的是不可重新赋值的变量(值不可修改),var定义的是可重新赋值的变量(值可以修改),scala中声明变量是变量名称在前,变量类型在后。跟java是正好相反scala的语句最后不需要添加分号
例子:
//使用val声明变量,相当于java中的final修饰,不能在指向其他的数据了
val a: Int = 3
//使用var声明变量,后期可以被修改重新赋值
var b: Int = 2
b=10
//scala中的变量的类型可以显式的声明,也可以不声明,如果不显式的声明这会根据变量的值来推断出来变量的类型(scala支持类型推断)
val c = 5
2、惰性变量
Scala中使用关键字lazy来定义惰性变量,实现延迟加载(懒加载)。惰性变量只能是不可变变量,并且只有在调用惰性变量时,才会去实例化这个变量。
lazy val 变量名 = 表达式
3、基本数据类型
基础类型 | 类型说明 |
---|---|
Byte8 | 位带符号整数 |
Short16 | 位带符号整数 |
Int32 | 位带符号整数 |
Long | 64位带符号整数 |
Char | 16位无符号 |
Unicode | 字符 |
String | Char类型的序列(字符串) |
Float | 32位单精度浮点数 |
Double | 64位双精度浮点数 |
Boolean | true或false |
注意:scala类型与Java的一些区别
- scala中所有的类型都使用大写字母开头
- 整形使用Int而不是Integer
- scala中定义变量可以不写类型,让scala编译器自动推断
4、scala类型层次结构
如图:
类型 | 说明 |
---|---|
Any | 所有类型的父类,它有两个子类AnyRef与AnyVal |
AnyVal | 所有数值类型的父类 |
AnyRef | 所有对象类型(引用类型)的父类 |
Unit | 表示空,Unit是AnyVal的子类,它只有一个的实例(),它类似于Java中的void,但scala要比Java更加面向对象 |
Null | Null是AnyRef的子类,也就是说它是所有引用类型的子类。它的实例是null, 可以将null赋值给任何对象类型 |
Nothing | 所有类型的子类不能直接创建该类型实例,某个方法抛出异常时,返回的就是Nothing类型,因为Nothing是所有类的子类,那么它可以赋值为任何类型 |
5、scala中的条件表达式
条件表达式就是if表达式,if表达式可以根据给定的条件是否满足,根据条件的结果(真或假)决定执行对应的操作。scala条件表达式的语法和Java一样。
//定义变量x
scala> val x =1
x: Int = 1
//if表达式
scala> val y =if(x>0) 1 else -1
y: Int = 1
//支持混合类型表达式
scala> val z = if(x>1) 1 else "error"
z: Any = error
//缺失else 相当于 if(x>2) 1 else ()
scala> val m=if(x>2) 1
m: AnyVal = ()
//scala中有个Unit类,用作不返回任何结果的方法的结果类型,相当于Java中的void,Unit只有一个实例值,写成()
scala> val n=if(x>2) 1 else ()
n: AnyVal = ()
//if(xx) else if(xx) val
scala> val k=if(x<0) -1 else if (x==0) 0 else 1
k: Int = 1
6、scala方法的重载
Scala也提供了方法重载功能,使我们能够定义相同名称但使用不同参数或数据类型的方法。 它有助于优化代码。
示例:
class Arithmetic{
def add(a:Int, b:Int): Unit = {
val sum = a + b
println(sum)
}
def add(a:Int, b:Int, c:Int): Unit = {
val sum = a + b + c
println(sum)
}
def add(a: Double, b: Double): Unit = {
val sum = a + b
println(sum)
}
}
object Demo{
def main(args:Array[String]){
val arithmetic = new Arithmetic()
arithmetic.add(1, 2)
arithmetic.add(1, 2, 3)
arithmetic.add(1, 2.6)
}
}
示例二:
+-*/%
上面的运算符,分别为加、减、乘、除、取余,功能上和Java中相同的工作,但在scala中他们都是方法,这是典型的使用scala方法重载的例子。tip:scala中几乎可以用任何符号来为方法命名。
例子:
scala> 1 + 2
等同于:
scala> 1.+(2)
7、scala中的块表达式
定义变量时用 {} 包含一系列表达式,其中块的最后一个表达式的值就是块的值。
val x=0
val result={
val y=x+1
val z=y+"hello"
val m=z+"scala"
"I like use scala"
}
上面代码中,result的值就是块表达式的结果,不需要加上return,只要把返回的结果放在方法的最后一行就可以了。
8、循环
在scala中,可以使用for和while
1、for循环
for (i <- 表达式/数组/集合 if i条件){
//表达式
}
//简单的for循环
scala> val nums= 1 to 5
nums: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5)
scala> for(i <- nums) println(i)
1
2
3
4
5
//双重for循环
scala> for(i <- 1 to 3; j <- 1 to 3) println(i*10+j)
11
12
13
21
22
23
31
32
33
for循环的使用还有两个特殊的概念
- 守卫
在for表达式中可以添加if判断语句,这个if判断就称为守卫,if为true,才会执行for语句的块
//语法结构
for(i <- 表达式/数组/集合 if 表达式) {
// 表达式
}
示例:
scala> for(i <- 1 to 8 if i >5) println(i)
6
7
8
- for推导式
在for循环体中,可以使用yield表达式构建出一个集合,我们把使用yield的for表达式称之为推导式
val v = for(i <- 1 to 5) yield i * 10
2、while循环
scala中while循环和Java中结构是一致的
while(返回值为布尔类型的表达式){
//表达式
}
示例:
scala> var x = 8
x: Int = 8
scala> while(x > 5){
println(x)
x -= 1
}
8
7
6
9、方法和函数
在scala当中,函数与方法是两个不同的概念,函数是scala当中的一等公民,scala是一门函数式的编程语言,同时兼顾了面向对象语言的特性。
- 方法与函数的定义方式不同
- 方法可以转换成为函数
- 函数就是对象
- 函数可以作为方法的参数
- 函数可以作为方法的返回值
1、方法
def methodName (参数名:参数类型, 参数名:参数类型) : [return type] = {
// 方法体:一系列的代码
}
示例一:
def hello(first: String, second: Int): Int = {
second
}
示例二:定义一个方法,且不定义返回值
注意:如果定义的方法没有返回值,那么方法的返回值会做自动推断。根据我们方法的最后一个返回类型来推断我们的方法返回类型
def hello2(first:Int , second:String) ={
//println(first)
//20
}
val hello2Result = hello2(20,"abc")
println( hello2Result)
示例三:定义一个方法,不定义返回值,可以通过自动推断,返回不同类型的值
def hello3(first:Int,second:String) ={
if(first > 10){
first
}else{
second
}
}
val hello3Result = hello3(5,"helloworld")
println(hello3Result)
示例四:定义一个方法,参数给定默认值,如果不传入参数,就使用默认值来代替
def hello4(first:Int = 10,second:String)={
println(first+"\t"+ second)
}
//注意我们在调用方法的时候我们可以通过参数名来指定我们的参数的值
hello4(second="helloworld")
示例五:变长参数,方法的参数个数不定的,类似于java当中的方法的...可变参数
def hello5(first:Int*)={
var result = 0;
for(arg <- first){
result += arg
}
println(result)
}
hello5(10,20,30)
hello5(10,50)
示例六:递归函数。我们可以定义一个方法,使得方法自己调用自己,形成一个递归函数,但是方法的返回值类型必须显示的手动指定
def hello6(first:Int):Int={
if(first <= 1){
1
}else{
first * hello6(first -1)
}
}
val hello6Result = hello6(10)
println(hello6Result)
示例七:定义一个方法,没有显示的指定返回值,那么我们方法当中定义的等号可以省掉
注意:如果省掉了=号,那么这个方法强调的就是一个代码执行的过程
/**
* 定义了一个方法,但是方法的返回值没有显示指定,
* 此时我们就可以省掉方法定义的=号,如果省掉 = 号,
* 那么这个方法强调的是一个过程,代码执行的过程,
* 不会产生任何的返回值
* @param first
*/
def hello7(first:Int){
println(first)
30
}
println(hello7(20))
示例八:直接通过def定义一个方法
def hello8=10
val hello8Result = hello8
println(hello8Result)
示例九:如果方法体当中只有一行代码,我们也可以省掉大括号
def hello10(first:Int,second:Int) = first+second
val hello10Result = hello10(10,20)
println(hello10Result)
2、函数
函数定义的两种形式第一种形式:
val 函数名 = (参数名1:参数类型1,参数名2:参数类型2) => {函数体}
第二种形式:
val 函数名:(参数类型1,参数类型2) => (返回类型) = {
函数体
}
示例一:定义一个标准函数,使用 =>来进行定义
val func1 =(x:Int,y:Int) =>{
x+y
}
func1(2,8)
示例二:定义匿名函数。也就是我们可以定义一个没有名字的函数定义一个匿名函数之后,这个函数就没法使用了
(x:Int,y:String) =>{x + y}
示例三:函数定义的另外一种形式,定义一个函数,参数只有一个且是Int类型,返回值也是Int类型
val func3 :Int => Int = {x => x * x }
val func3Result = func3(10)
示例四:定义一个函数,参数值是两个,分别是Int和String,返回值是一个元组,分别是String和Int
val func4:(Int,String) =>(String,Int) ={
(x,y) => (y,x)
}
val func4Result = func4(10,"hello")
println(func4Result)
3、方法和函数的区别
方法是隶属于类或者对象的,在运行时,它是加载到JVM的方法区中可以将函数对象赋值给一个变量,在运行时,它是加载到JVM的堆内存中。函数是一个对象,继承自FunctionN,函数对象有apply,curried,toString,tupled这些方法,而方法则没有
4、方法转换为函数
有时候需要将方法转换为函数,作为变量传递,就需要将方法转换为函数使用,下面为将方法转换为函数示例
scala> def add(x:Int,y:Int)=x+y
add: (x: Int, y: Int)Int
scala> val a = add _
a: (Int, Int) => Int = <function2>