欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Scala基础

程序员文章站 2022-06-14 17:02:18
...

1 安装Scala

1.1 Win安装scala环境

  访问Scala官网http://www.scala-lang.org/下载Scala编译器安装包,解压后配置上环境变量就可以了。

1.2 Linux安装scala环境

  a) 下载Scala,地址https://www.scala-lang.org/download/2.12.6.html
  b) 然后解压Scala到指定目录:tar -zxvf scala-2.12.6.tgz -C /usr/local/src
  c) 配置环境变量,将scala加入到PATH中

vi /etc/profile
export SCALA_HOME=/usr/local/src/scala-2.12.6
export PATH=$PATH:$SCALA_HOME/bin

1.3 IDEA安装scala插件

  Configure -> Plugins -> Browse Repositories -> 搜索Scala -> 找到Scala LANGUAGES -> 点击右侧的Install -> 重启IDEA

2 Scala基础

2.1 声明变量

//使用val定义的变量值是不可变的,相当于java里用final修饰的变量
val i = 1

//使用var定义的变量是可变得,在Scala中鼓励使用val
var s = 2

//Scala编译器会自动推断变量的类型,必要的时候可以指定类型
//变量名在前,类型在后
val str: String = "hello scala"
println(i + "," + s + "," + str)

2.2 条件表达式

val x = 1

//判断x的值,将结果赋给y
val y = if (x > 0) 1 else -1
println("y:" + y)

//支持混合类型表达式
val z = if (x > 1) 1 else "error"
println("z:" + z)

//如果缺失else,相当于if (x > 2) 1 else ()
val m = if (x > 1) 1
println("m:" + m)

//在scala中每个表达式都有值,scala中有个Unit类,写做(),相当于Java中的void
val n = if (x > 1) 1 else ()
println("n:" + n)

//if和else if
val k = if (x > 1) 1 else if (x > 0) 0 else -1
println("k:" + k)

2.3 块表达式

val x = 0
//在scala中{}中课包含一系列表达式,块中最后一个表达式的值就是块的值
val result = {
  if(x > 0) 1 else if(x == 0) 0 else -1
}
//result的值就是块表达式的结果
println("result: " + result)

2.4 For循环

//for(i <- 表达式),表达式1 to 10返回一个Range(区间)
//每次循环将区间中的一个值赋给i
for (i <- 1 to 10) {
  print(i + ",")
}
println()

//for(i <- 数组)
val arr = Array("a", "b", "c")
for (i <- arr) {
  print(i + ",")
}
println()

//高级for循环,每个生成器都可以带一个条件,注意:if前面没有分号
for (i <- 1 to 3; j <- 1 to 3 if i != j) {
  print(i*10 + j + ",")
}
println()

//for推导式:如果for循环的循环体以yield开始,则该循环会构建出一个集合
//每次迭代生成集合中的一个值
val v = for(i <- 1 to 10) yield i * 10
println(v)

2.5 函数和方法

object ScalaTest2 {

  //定义一个方法,方法由def开始,m1为方法名,括号内为参数,括号右边是返回值,等号右边为表达式
  def m1 (x:Int, y: Int) : Int = x * y
  //返回值可以不写,scala会自动识别,但是递归方法,必须指定返回值
  def m2 (x: String, y: String) = x + y

  //定义函数
  //定义了一个匿名函数,左边为参数列表,右边是表达式,该函数没由变量引用,即匿名函数,同时没写返回值
  (x: Int, y: Int) => (x + y)

  //普通函数,即有变量引用的函数
  val f1 = (x: String, y: String) => {x + y}
  val f2 = (x: Int) => x * 10
  val f3 = (x: Int) => x + 10

  //将函数传入方法中
  val f4 = (x: Int) => x * 10
  def m3 (f: Int => Int) : Int = {
    //方法中调用传入的函数
    f(3)
  }

  //将方法转化为函数
  def m4 (x : Int, y: Int) : Int = x * y

  def main(args: Array[String]): Unit = {
    //调用方法
    println(m1(2, 4))
    println(m2("Hello ", "World"))

    //调用函数
    println(f1("Hello ", "Scala"))

    //在函数式编程语言中,函数是“头等公民”,它可以像任何其他数据类型一样被传递和操作
    //其实就是把函数f2,f3的功能给传递到方法中,执行函数的功能
    //这里就是把f2的x*10传入map方法,执行了x*10,把f3的x+10传入map方法,执行了x+10
    val r = 1 to 10
    println(r.map(f2))
    println(r.map(f3))

    //函数传入方法
    println("函数传入方法中,结果为:" + m3(f4))

    //三种相同功能的不同写法
    println(r.map((x: Int) => x * 100)) //map中传入一个匿名函数,参数为Int,功能是map取出的每个元素*100
    println(r.map(x => x * 100)) //既然知道传入的必然是Int,则参数可以不写,即:map每个元素赋予x,功能是x*100
    println(r.map(_ * 100)) //再可以直接简写为_

    val a2 = Array(1,2,3,4,5,6)
    //map中传入匿名函数
    val r1 = a2.map(x => x * 10)
    val r2 = a2.map(x => x - 10)
    //这样打印的是地址
    println(r1)
    //scala中用toBuffer查看里面的内容
    println(r1.toBuffer)
    //还是输出的是地址
    println(r1.toString)
    println(r2.toBuffer)
    println(a2.toBuffer)

    //将方法转化为函数,神奇的下划线
    val f5 = m4 _
    println(f5(3, 2))
  }
}

3 数组、映射、元组、集合

3.1 数组

3.1.1 定长数组和变长数组

 (1)定长数组定义格式:val arr=new Array[T](数组长度) 或val arr=Array[T](元素…)
 (2)变长数组定义格式: val arr = ArrayBuffer[T]()
  注意需要导包:import scala.collection.mutable.ArrayBuffer

//初始化一个定长数组,new出来的并且括号中赋值数组,相当于调用了数组的apply方法,直接为数组赋默认值,这里为0
val arr1 = new Array[Int](8)
//直接打印定长数组,内容为数组的hashcode值
println(arr1)
//将数组转换成数组缓冲,就可以看到原数组中的内容了,toBuffer会将数组转换长数组缓冲
println(arr1.toBuffer)

//初始化一个定长数组,自己指定值
//这里没用new,为自己赋值,这里是长度为1的数组,值为10
val arr2 = Array[Int](10)
println(arr2.toBuffer)

//定义一个长度为3的定长数组
val arr3 = Array[String]("Hello", "World", "Scala")
//使用下标来访问数组中元素
println(arr3(1))

/********************变长数组 *****************************/

//变长数组(数组缓冲)
//如果想使用数组缓冲,需要导入import scala.collection.mutable.ArrayBuffer包
val array4 = ArrayBuffer[Int]()
//+=向数组缓冲的尾部追加一个元素
array4 += 1
println(array4)

//尾部追加多个元素
array4 += (2, 3, 4, 5)
println(array4)

//追加一个数组,追加数组和数组缓冲需要用 ++=
array4 ++= Array(6, 7)
println(array4)

//追加一个数组缓冲,需要用++=
array4 ++= ArrayBuffer(8, 9)
println(array4)

array4.insert(0, -1, 0)
println(array4)

//删除数组某个位置的多个元素用remove
//从第9个位置删除两个元素
array4.remove(9, 2)
println(array4)

3.1.2 遍历数组

val array5 = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
//增强for输出
for (i <- array5) print(i + ",")
println()

//until循环赋值
for (i <- (0 until array5.length)) print(array5(i) + ",")
println()

3.1.3 数组转换

//将原数组的每个元素乘以10放入一个新的数组,yield把每个元素做对应操作后放入一个新的数组
val res = for (i <- array5) yield i * 10
println(res.toBuffer)

//取原数组元素中的偶数+10放入一个新的数组,在for中加if过滤
val res1 = for(i <- array5 if i % 2 == 0) yield i * 10
println(res1.toBuffer)

//更高级的写法,filter过滤,接收一个返回值为boolean的函数
//_下划线表示每次取出的元素
//map相当于将数组中的每一个元素取出来,应用传进去的函数
val res2 = array5.filter(_ % 2 == 0).map(_ * 10)
println(res2.toBuffer)

3.1.4 数组常用算法

//求和
println(array5.sum)
//求最大值
println(array5.max)
//数组排序,正序
println(array5.sorted.toBuffer)
//数组排序,倒序
println(array5.sorted.reverse.toBuffer)

3.2 映射

3.2.1 映射的声明

//在Scala中,有两种Map,一个是immutable包下的Map,该Map中的内容不可变;另一个是mutable包下的Map,该Map中的内容可变
//(1)不可变的Map   import scala.collection.immutable._
// 创建map的第一种方式,用箭头
val map1 = Map("zhangsan" -> 18, "lisi" -> 20)
println(map1)

//创建map的第二种方式,用元组
val map2 = Map(("zhangsan", 20), ("lisi", 18))
println(map2)
//通常我们在创建一个集合是会用val这个关键字修饰一个变量(相当于java中的final),
//那么就意味着该变量的引用不可变,该引用中的内容是不是可变,取决于这个引用指向的集合的类型

//(2)可变的Map  import scala.collection.mutable._
val user = HashMap("zhangsan" -> 20, "lisi" -> 18)
println(user)

3.2.2 不可变映射的操作

//获取和修改Map中的值,通过key获取map的value
println(map2("zhangsan"))
println(map2.get("lisi"))
println(map2.get("lisi").get)

//如果map中没有该key,则会报错,可以使用map.getOrElse(key, defalut)
//println(map2("wangwu"))
println(map2.getOrElse("wangwu", "null"))

//遍历map集合
//方法一:显示所有的key
val keys: Iterable[String] = map2.keys
println(keys)
for(i <- keys) println(i + "-->" + map2(i))
println()

//方法二:显示所有的key
val set: Set[String] = map2.keySet
println(set)
for(i <- set) println(i + "-->" + map2(i))
println()

//通过元组
for((i, j) <- map2) println(i + "-->" + j)
println()

//通过模式匹配
map2.foreach{
    case (x, y) => println(x + "-->" + y)
}

3.2.3 可变映射的操作

//添加键值对
user += ("wangwu" -> 19)
println(user)

//添加多个键值对
user += (("zhaoliu", 22), "tianqi" -> 23)
println(user)

//更新键值对
user("zhangsan") = 15
println(user)

//更新多个键值对
user += ("zhangsan" -> 33, "lisi" -> 40)
user.put("wangwu", 40)
println(user)

//删除key
user -= ("zhangsan")
user.remove("lisi")
println(user)

3.3 元组

3.3.1 创建元组

  * 映射是K/V对偶的集合,对偶是元组的最简单形式,元组可以装着多个不同类型的值
  * (1)元组是不同类型的值的聚集;对偶是最简单的元组。
  * (2)元组表示通过将不同的值用小括号括起来,即表示元组
  * 创建元组格式:val tuple=(元素,元素...)
  */
val t = ("hadoop", "storm", "spark")
println(t)

val t1 = ("hadoop", 3.14, 10, true)
println(t1)

3.3.2 获取元组的值

/**
  * (1) 获取元组中的值格式:
  * 使用下划线加脚标 ,例如 t._1  t._2  t._3
  * 注意:元组中的元素脚标是从1开始的
  */
println(t1._3)

3.3.3 对偶元组转集合

/**
  * 将对偶的集合转换成映射:
  * 调用其toMap方法
  */
val t2 = Array(("tom", 20), ("jerry", 18))
println(t2.toMap)

3.3.4 拉链操作

/**
  * 拉链操作
  * 1.使用zip命令可以将多个值绑定在一起
  *     如果两个数组的元素个数不一致,拉链操作后生成的数组的长度为较小的那个数组的元素个数
  * 2.如果其中一个元素的个数比较少,可以使用zipAll用默认的元素填充
  */
val t3 = Array("tom", "jerry", "hello")
val t4 = Array(18, 19)
println(t3.zip(t4).toList)

//拿一个wangwu来凑数,使hello有匹配到值20
println(t3.zipAll(t4, "wangwu", 20).toList)

3.4 集合

  Scala的集合有三大类:序列Seq、Set、映射Map,所有的集合都扩展自Iterable特质,在Scala中集合有可变(mutable)和不可变(immutable)两种类型,immutable类型的集合初始化后就不能改变了(注意与val修饰的变量进行区别)

在Scala中列表要么为空(Nil表示空列表),要么是一个head元素加上一个tail列表
list常用的操作符:
+: (elem: A): List[A] 在列表的头部添加一个元素
:: (x: A): List[A]     在列表的头部添加一个元素
:+ (elem: A): List[A] 在列表的尾部添加一个元素
++[B](that: GenTraversableOnce[B]): List[B] 从列表的尾部添加另外一个列表
::: (prefix: List[A]): List[A] 在列表的头部添加另外一个列表

3.4.1 List

  (1)不可变的序列 import scala.collection.immutable._

(2)//创建一个不可变的集合
val list1 = List(1,2,3)
//另一种定义list方法
val list2 = 2 :: Nil
println("list2: " + list2)
//获取集合的第一个元素,head元素
val first = list1.head
println("first: " + first)
//获取tail列表
val tail = list1.tail
println("tail: " + tail)
//通过下标获取元素
val mid = list1(1)
println("mid: " + mid)

//如果 List 中只有一个元素,那么它的 head 就是这个元素,它的 tail 就是 Nil;
println(list2.head + "-->" + list2.tail)

//将0插入到list1的前面生成一个新的List
val list3 = 0 :: list1
println("list3: " + list3)
println("list3: " + list1.+:(0))
val list4 = 0 +: list1
println("list4: " + list4)
println("list4: " + list1.+:(0))

//将一个元素添加到lst1的后面产生一个新的集合
val list5 = list1 :+ 0
println("list5: " + list5)
println("list5: " + list1.:+(0))

//将2个list合并成一个新的List
val list6 = List(4,5,6)
println(list1 ++ list6)
println(list1.++(list6))

//将list6插入到list1前面生成一个新的集合
println(list6 ++ list1)
println(list1.:::(list6))

  (2)可变的序列 import scala.collection.mutable._

(3)//构建一个可变列表,初始有3个元素1,2,3
val blist = ListBuffer[Int](1,2,3)
//创建一个空的可变列表
val blist1 = new ListBuffer[Int]

//向lst1中追加元素,注意:没有生成新的集合
blist1 += 4
blist1.append(5)
blist1.+=(6)
println("blist: " + blist)
println("blist1: " + blist1)

//将blist1中的元素追加到blist中, 注意:没有生成新的集合
blist ++= blist1
println("blist: " + blist)

//将blist和blist1合并成一个新的ListBuffer 注意:生成了一个集合
val blist2 = blist ++= blist1
println("blist2: " + blist2)

//将元素追加到blist的后面生成一个新的集合
val blist3 = blist :+ 4
println("blist3: " + blist3)

//从集合左侧删除元素,注意:没有生成新的集合
blist3 -= 4
println("blist3: " + blist3)

//删除一个集合列表
blist3 --= List(1,2)
println("blist3: " + blist3)

//删除一个集合列表,生成了一个新的集合
val blist4 = blist3 -- List(6,4)
println("blist4: " + blist4)

//把可变list 转换成不可变的list 直接加上toList
val blist5 = blist4.toList
println("blist5: " + blist5)

3.4.2 Set

  Set代表一个没有重复元素的集合;将重复元素加入Set是没有用的,而且 Set 是不保证插入顺序的,即 Set 中的元素是乱序的。定义:val set=Set(元素,元素,…)
  (1) 不可变的Set import scala.collection.immutable._

//定义一个不可变的Set集合
val set = Set(1,2,3,4,5)
//元素个数
println("元素个数: " + set.size)
//取集合最小值
println("集合最小值: " + set.min)
//取集合最大值
println("集合最大值: " + set.max)
//添加元素,生成新的set,原有set不变
println(set + 6)

val set1 = Set(1,2,6,7,8,9)
//两个集合的交集
println("交集:" + (set & set1))
//两个集合的并集
println("并集:" + (set | set1))
println("并集:" + (set ++ set1))
//返回第一个不同于第二个set的元素集合
println("差集:" + (set -- set1))
println("差集:" + (set &~ set1))
println("差集:" + set.diff(set1))
//计算符合条件的元素个数
println("符合条件的元素个数:" + set.count(_ > 2))
//取子set,包含头不包含尾)
println(set.slice(2, 5))
//迭代所有的子set,取指定的个数组合
set.subsets(3).foreach(x => println("当前子set: " + x))

  (2) 可变的Set import scala.collection.mutable._

//定义一个可变的Set
val set2 = new HashSet[Int]()
//添加元素
set2.add(2)
set2.+=(3)
println("添加元素:" + set2)
//向集合中添加元素集合
println("添加集合:" + (set2 ++= Set(3,4,5)))
//删除一个元素
set2 -= 5
set2.remove(4)
println("删除元素:" + set2)

忙会工作,未完待续。。。