Scala基础(一)
一、什么是Scala:
直观的来说,加强版Java。一种以Java虚拟机(JVM)为运行环境的静态类型编程语言。可以直接使用Java的类库。(拥有者强大的编译器)
特点:面向对象,函数式编程
Scala有三类事务,Class、Object、Trait。在Scala中把静态的和非静态的严格分开
Class中编写非静态的东西;
Object中只能编写静态的,我例如Java中的main方法,它是静态的,在Scala中就要写道Object里。
简单的举个例子:
object Scala { def func1 = println("Hello Zyp") def main(args: Array[String]): Unit = { /* 写个main方法,直接调用函数 */ func1 } }
在上面的代码中:
1. object里面都是静态方法(以及变量等)
2. 数据类型跟在变量后面,中间用“ :”隔开
3. 返回值在参数完成的后面,方法体是以“ = ”来赋值
4. 语句末有无 ”;“ 都可
在Scala中我们声明" func1 "这个函数,他其实是个变量,这就是这个语言不同于java的地方,完全面向对象编程,是函数语言。每一个函数在Scala中都是一个值,当我们定义一个函数的时候就是定义了一个变量。
Scala中的函数:高阶函数、柯里化函数、内嵌函数(函数中定义函数)等。
高阶函数: 函数的参数可以传递函数
克里化函数: 函数可以拆分,部分执行。
二、Scala中的变量和函数:
1. 定义变量:
修饰符:var \ val
var 代表一个变量 ;val 代表一个常量
def main(args: Array[String]): Unit = { var n =10 n=11 //变量可以再次赋值 } def main(args: Array[String]): Unit = { val n:Int =10 n=11
//会报错 Reassignment to val }
从上面的声明变量还可以看出:在Scala中,类型可以不给。(Scala中没有基本数据类型,全是引用数据类型)
变量的几种输出方式:
object Program1 { def main(args: Array[String]): Unit = { var name: String = "zhangsan" var age = 10 var tall = 180.65f /* 字符串的三种输出方式: */
// 方式一: println(age+"\t"+name)
// 方式二: printf("数字是%d 字符串是%s 小数是%.4f",age,name,tall)
// 方式三:
// 格式化输出,其中 s:String d:Int f:float
println(s"个人信息如下:\n名字:$name 年龄:${age+15} 身高:$tall") // 前面的s标记相当于告诉编译器,后面$跟着变量 而且${}中的{}里面是一个表达式 } }
打印结果如图:
2. 定义函数:
关键字:def
def func2(a:Int,b:Int):Int = return a+b
1. 返回值关键字 "return" 可写可不写
2. :Int 表示的是返回值类型,没有返回值就是Unit
3. 这里的参数类型是变量,也可以用函数作为参数(因为scala中一切皆对象)
例如:
def square(x: Int) = { println(x) x * x } def printByName(x: => Any): Unit = { println(x) } def main(args: Array[String]): Unit = { printByName(square(5)) }
先执行square,把整个函数作为参数传递给X,那么就会先打印5再返回25
3. scala中的循环:
打印1-10:
for (i <-1 to 10){ println(i) }
-- 从1到10全部都打印;
而 1 until 10 则打印的是1到9,不包括10
隔两个打印一个数隔两个打印一个数:(步长为2)
for (i <-1 to 10 by 2){ //by 自增的意思 print(i+" ") }
// 等同于Range()
for (i <-Range(1,10,2)){
print(i+" ") }
打印结果为:
1 3 5 7 9
用ForEash的方式:
(1 to 10 by 2).foreach( println(_) _的意思是当前,当前这个数 ) 但是你如果不想用下划线的话可以如下: (1 to 10 by 2).foreach( 推出的方式 x =>println(x) )
补充一个yield的用法:
常用场景:将元素自动封装到集合中 val temp = for(i <- 1 to 100; if i%2 == 0) yield i //此时rest就为选择出的i构成的一个集合 for(elem <- rest) println(elem)
4. Scala中的数据类型:
Scala所有类型都是Object,顶级的类叫做ScalaObject.我们定义的所有的类都叫做ScalaObject。ScalaObject下面呢就是最根基的类叫做Any,就是任意类型,下面两个体系:值类型(AnyVal)和引用类型(AnyRef)
数值这些类型(Int Boolean char..)归为值类型(AnyVal)
String和数组,列表这些都归为引用类型(AnyRef)
Null:是一个类,只有一个值:null。是所有AnyRef(引用)类型的子类
Nothing:没有实例对象的一种数据类型,它是所有类的子类。(可以将Nothing类型的值返回给任意类型的变量或者函数)
Unit:代表的是一个值类型,类似于Java中void
5. 函数:
大致简单介绍下,抽空详细的列举下算子。
5.1 普通函数:
def fun (a: Int , b: Int ) : Unit = { println(a+b) } fun(1,1) def fun1 (a : Int , b : Int)= a+b println(fun1(1,2))
5.2 包含参数默认值的函数:
/** * 包含参数默认值的函数 * 1.函数的参数有默认值,在调函数的时候可以传参,也可以不传参, * 2.若不传参使用的默认值, * 3.如果传参,默认值会被覆盖 */ def fun2(num1:Int = 10,num2:Int = 20) = { num1 + num2 } def fun3(num1:Int,num2:Int = 20) = { num1 + num2 } def fun4(num1:Int=10,num2:Int) = { num1 + num2 } 调用: println(fun2()) println(fun3(100)) println(fun4(num2=1000))
5.3 可变参数个数的函数:(参数个数可以是一个也可以是多个)
def fun5(args:Double*) = { /** * 在scala中 * +=前后的数值类型必须一致 * +前后的数值类型可以不一致 */ var sum = 0.0 for(arg <- args) sum += arg sum }
5.4 匿名函数:
/** * 匿名函数 * 1.有参数的匿名函数 * 2.无参数的匿名函数 * 3.有返回值的匿名函数 * 注意: * 可以将匿名函数返回给定义的一个变量 * 匿名函数不能显式声明函数的返回类型 */ //有参数匿名函数 val value1 = (a : Int) => { println(a) } value1(1) //无参数匿名函数 val value2 =()=>{ println("Hello Scala") } value2() //有返回值的匿名函数 val value3 = (a:Int,b:Int) =>{ a+b } println(value3(4,4))
5.5 偏函数:
作用于指定类型的参数或指定范围值的参数实施计算,超出它的界定范围之外的参数类型和值它会忽略(未必会忽略,这取决于你打算怎样处理)。简单来讲:给出的参数中,只根据你在方法体中规定的条件进行甄别,符合条件的就操做,不行的直接滤掉(取决于你业务上的逻辑处理)。
举个简单的例子体会下:
三、Tuples元组
1. 什么是元组?
用来包含一组不同类型的值。例如:名字,年龄,出生日期....元组的元素是不可变的。它的本体可以作为一个参数进行传递。元组是有上限的,最多只能有22个,超出的话建议使用集合。
2. 定义一个元组:
val t1 = (1, "hello", true) -- 简写形式,常用,这里声明为常量,值不可变 -- 如果只有两个元素,还可以写成:
val t2 = 1 -> "world"
println(tuple1) println(tuple1._1) -- 1 println(tuple2._2) -- hello
上面代码可以看出,我们通过" ._1 "来获取元组中对应下标的元素(下标是从1开始的)
3. 遍历元组:
上面2中可以直接打印元组,也可以取出元组中某个位置上的值;那么如何遍历所有元素呢?
这里要用到Tuple.productIterator()方法,获取迭代器以后再循环遍历:
tuple1.productIterator.foreach(i=>println(i))
或者
for (i <- tuple1.productIterator){
println(i)
}
}
}
四、数组
Scala中的数组分为 定长数组Array 和 变长数组ArrayBuffer 。存储的是固定大小的同类型元素。
定长数组:
- 数组的长度不允许改变
- 数组中的元素可以改变
语法:
// 通过指定长度定义数组 val/var 变量名 = new Array[元素类型](数组长度) // 用元素直接初始化数组 val/var 变量名 = Array(元素1, 元素2, 元素3...)
注意:
- 在Scala中,数组的泛型用 [ ] 来指定;
- 用()来获取元素
示例一:
- 定义一个长度为100的整型数组
- 设置第1个元素为110
- 打印第1个元素
scala> val a = new Array[Int](100) a: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) scala> a(0) = 110 scala> println(a(0)) 110
示例二:
-
定义一个包含以下元素的数组:
"java", "scala", "python"
-
获取数组长度
// 定义包含jave、scala、python三个元素的数组 scala> val a = Array("java", "scala", "python") a: Array[String] = Array(java, scala, python) scala> a.length res17: Int = 3
变长数组:
- 数组的长度是可变的;
- 可以向数组中添加、删除元素
语法:
// 创建空的ArrayBuffer变长数组,语法结构: val/var a = ArrayBuffer[元素类型]() // 创建带有初始元素的ArrayBuffer val/var a = ArrayBuffer(元素1,元素2,元素3....)
示例:
定义一个包含以下元素的变长数组:"hadoop", "storm", "spark"
scala> val a = ArrayBuffer("hadoop", "storm", "spark")
a: scala.collection.mutable.ArrayBuffer[String] = ArrayBuffer(hadoop, storm, spark)
区间数组:
使用 range() 方法来生成一个区间范围内的数组。range() 方法最后一个参数为步长,默认为 1:
import Array._ object Test { def main(args: Array[String]) { var myList1 = range(10, 20, 2) // 步长为2 var myList2 = range(10,20) // 不写默认步长为1 // 输出所有数组元素 for ( x <- myList1 ) { print( " " + x ) } println() for ( x <- myList2 ) { print( " " + x ) } } } 输出结果为: $ scalac Test.scala $ scala Test 10 12 14 16 18 10 11 12 13 14 15 16 17 18 19
添加、修改、删除元素:
- 使用
+=
添加元素 - 使用
-=
删除元素 - 使用
++=
追加一个数组到变长数组
示例:
- 定义一个变长数组,包含以下元素: “hadoop”, “spark”, “flink”;
- 往该变长数组添加一个"flume"元素;
- 从该变长数组删除"hadoop"元素;
- 再将一个数组,该数组包含"hive", "sqoop"追加到变长数组中;
// 定义变长数组 scala> val a = ArrayBuffer("hadoop", "spark", "flink") a: scala.collection.mutable.ArrayBuffer[String] = ArrayBuffer(hadoop, spark, flink) // 追加一个元素 scala> a += "flume" res10: a.type = ArrayBuffer(hadoop, spark, flink, flume) // 删除一个元素 scala> a -= "hadoop" res11: a.type = ArrayBuffer(spark, flink, flume) // 追加一个数组 scala> a ++= Array("hive", "sqoop") res12: a.type = ArrayBuffer(spark, flink, flume, hive, sqoop)
遍历数组:
两种方式:
- 使用
for表达式
直接遍历数组中的元素 - 使用
索引
遍历数组中的元素
scala> val a = Array(1,2,3,4,5) a: Array[Int] = Array(1, 2, 3, 4, 5) scala> for(i<-a) println(i)
scala> a.foreach(x => { println(x) })
1 2 3 4 5
scala> val a = Array(1,2,3,4,5) a: Array[Int] = Array(1, 2, 3, 4, 5) scala> for(i <- 0 to a.length - 1) println(a(i)) 1 2 3 4 5 scala> for(i <- 0 until a.length) println(a(i)) 1 2 3 4 5
注意:
0 until n : 遍历0到n-1,不包括n
0 to n ——遍历0到n,包含n
数组的函数:
参见https://blog.csdn.net/zyp13781913772/article/details/81428862
五、集合
Scala集合分为可变的和不可变的集合。
(可变集合可以在适当的地方被更新或扩展。这意味着你可以修改,添加,移除一个集合的元素。
而不可变集合类,相比之下,永远不会改变。不过,你仍然可以模拟添加,移除或更新操作。但是这些操作将在每一种情况下都返回一个新的集合,同时使原来的集合不发生改变。)
集合类型:
-
List:可重复切有序
- Set:不可重复无序
- 元组:存放的是不同类型的值(上面已经介绍过)
- Map:键值对;每个元素都是一组键值对
- Option:可能包含值的容器(也可能不含值)
- Iterator:迭代器不是一个容器,更准确的说是逐一访问容器内元素的方法
六、伴生类与伴生对象
(区别于Java来看)
在同一个文件中,Class与Object同名,构成伴生类和伴生对象
我们已经知道,class里的相当于Java中的成员变量和成员方法,使用时需要通过new一个对象来调用,而object中则全是静态的,不需要对象调用就可以直接使用。而在伴生类和伴生对象中,如果你在伴生对象里,写了apply方法,那么此时可以通过伴生对象直接来调用伴生类里的方法(就不需要new一个对象来调用了,apply方法相当于就走了你的伴生类中的构造器)。
举例:
class ClassAndObject(name: String) { private var username = name def aaa() = { println("123") } } object ClassAndObject { def main(args: Array[String]): Unit = { //此时你想调用aaa方法,只能先new一个对象来调用 var c = new ClassAndObject() c.aaa } }
若想直接调用:
class ClassAndObject(name: String) { private var username = name def aaa() = { println("123") } } object ClassAndObject { def apply(name: String): ClassAndObject = new ClassAndObject(name) def main(args: Array[String]): Unit = { //此时就不需要再去new对象 ClassAndObject("zs").aaa() } }
本文来自博客园,作者:{理想三旬},转载请注明原文链接:{https://www.cnblogs.com/zyp0519/}