scala基础知识

目录

  • 1. 字符串
  • 2. 变量
    • 2.1 变量
    • 2. 2 三元运算符if
  • 3. 集合
    • 3.1 不可变集合
    • 3.2 可变集合:
  • 4. 高阶函数
  • 5. 循环
  • 6. Case| Match 关键字
    • 6.1 scala中的用法
    • 6.2 spark中case关键字的特殊用法
  • 7. 关键字 implicit
    • 7.1 隐式参数
    • 7. 2 隐式类
  • 8. 应用实战
    • 8.1 使用映射集合,统计一句话中,各个字母出现的次数
    • 8.2 集合的合并
    • 8.3 迭代器
  • 9. 函数
    • 9.1 函数返回值
    • 9.2 函数参数
    • 9.3 函数柯里化
  • 10. 类
    • 10.1 构造器
    • 10.2 继承
    • 10.3 方法重写
    • 10.4 实例

1. 字符串

  1. 字符串拼接 + | str_1.concat(str2)
  2. str.length(): 获取字符串的长度
  3. mkString: 将集合元素转化为字符串
  4. 采用stripMargin对多行字符串按照某种方式固定对齐,stripMargin默认是“|”作为出来连接符
  5. 处理字符串中的字符: map、filter、flatmap、foreach
object PrintDemo {
  def main(args: Array[String]): Unit = {
    val name:String = "tom"
    val age:Int = 10
    val heigh:Double = 175.5
    
    // 1. 字符串的打印方式: 1. println  2. printf 
    println("name=" +name +",age=" +age +",heigh=" +heigh)
    printf("name=%s, age=%d, heigh=%.2f\n",name,age,heigh)
    
    //2. mkString:将集合元素转化为字符串
    val a= Array("apple","banana","cherry")
    // 添加前后缀
	a.mkString("[", "-", "]")
	
	// 3. 将嵌套数组转化为字符串
	val b= Array(Array("a","b"), Array("c","d"))
	a.flatten.mkString(",")

	// 4. 对于大量转义字符及换行的字符串可以使用三个双引,使用“|”进行对其。
	val sql2 =
		s"""
	     |--曝光          // 左对齐
	     |load parquet.`${str2}` as t;
	     |select * from t as t1;
	   """.stripMargin
	   
	// 5. 访问、截取字符串,分隔字符
	val s1 = "World"
	val s2 = s1.substring(0,2) 
	val s3 = s1.split("l") 
	// 6. 处理字符串中的字符(map,filter,flatmap,for,foreach)
	val upper1 = s1.map(i=>i.toUpper)
	val upper2 = s1.map(_.toUpper)
	val filter = s1.filter(i=>i !='o')
	s1.foreach(println)
	for (i <- s1 if i != 'l') {
		println("i = "+i)
	}
	// 7. 字符串中的查找模式
	val pattern = "[0-9]+".r
	val address = "101 main street 123"
	val match1 = pattern.findFirstIn(address)
	val match2 = pattern.findAllIn(address)
	println(match1,match2)

	// 8.字符串中的替换模式
	val address1 = address.replaceAll("[0-9]","x")
	// 9. 抽取String中模式匹配的部分
	val pattern1 = "([0-9]+) ([A-Za-z]+)".r
	val pattern1(count,fruit) = "100 bananas"
	println(count,fruit)
  }
}
  1. _* 通配符,不定长参数

  2. :_* 作为一个整体,告诉编译器你希望将某个参数当作参数序列处理!例如val s = sum(1 to 5:_*) 就是将1 to 5当作参数序列处理

2. 变量

2.1 变量

val age = 26  // 定义的是不可变的 
var i = 10   // 定义可变变量
i += 1 
val r1 : Int = 10 / 3     // 3 [不会进行四舍五入]
val r2 : Double = 10 / 3 // a.先得到 3;  b. 3再转成3.0

2. 2 三元运算符if

val n1 = 20
val n2 = 40
val max = if (n1 > n2)  n1 else n2

3. 集合

Scala的集合有三大类:序列Seq、集合Set、映射Map,所有的集合都扩展自Iterable特质。

3.1 不可变集合

// scala.collection.immutable
// 1. 定长数组:array
val array = new Array[Int](5)
val x= (arr.max,arr.min,array.length) // 数组最值、长度
array(0)   //访问|更改数组
for (elem <- array) { println(elem) }     // 遍历数组
val a= Array(1,20,90)   //直接初始化
val b=Array(12,34,86)
val c= b++a // 合并数组 ++ ,若不同类型以左边为准,同union
val d= a++:b  //合并数组,并将右边的类型作为最终结果返回 ++:
// diff 去交集 intersect 取交集, +: 1+:array(2,3)在数组前面加一个元素
// 多维数组 Array.ofDim[Int](n1,n2), n1代表多个一维数组, n2代表每一个一维数组中有几个元素
val array = Array.ofDim[Int](3,4)
println(array(1)(1))  // 访问元素

// 2. 不可变list,必须初始化,列表有头部和尾部的概念,分别使用head和tail获取
val anyList = List[Any](10,20,"jack")
val value = anyList(2)     // 访问, 使用小括号和索引, 索引从0开始
val list1 = List[Any]("a","b","c")// 追加元素
val listAdd = list1 :+ "后面"
val addList = "前面" +:list1
val list3 = List[Any]("A","B","C")
val listAddMany = 1::2::3::list3::list1    //元素排列的顺序, 就是新对象中的顺序
val list4 = List[Any]("AA","BB","CC")
val listAddList = 4::5::6::list4:::list1  //元素排列的顺序, 就是新对象中的顺序

// 3. 元组, 可以理解为一个容器,可以存放各种相同或不同类型的数据,访问Tuple的元素的方式是 tuple._1 , tuple._2,tuple._3 ......

val myTuple = (1, 2, "hello")    // 创建
val a= new Tuple("1","hello")
println(myTuple.productElement(2)) //访问: 使用productElement(index), 索引从0开始

val iterator = myTuple.productIterator // 访问: 迭代器
iterator.foreach(println)
val iterator =myTuple.productIterator

// 4. 不可变map ,循环遍历映射: for((k,v) <- 映射),keys,values ,添加简直对,1.赋值添加  2. 使用+= 
import scala.collection.mutable
val map1 = Map("Alice" -> 10, "Bob" -> 20, "welldo" -> "27岁")    // 创建方式1
val map2 = Map(("Alice",10), ("Bob", 20), ("welldo" , "27岁"))   //创建方式2,使用元祖
if (map2.contains("aa")) {
	println("aa存在:" + map2("aa"))
    }else{
	println("aa不存在")
}
   
println(map2.getOrElse("aa", "this key is not exist"))      //如果key存在,返回key对应的值。 如果key不存在,返回默认值。

// 数组之间的相互转换
val m1 = Map(3 -> "geeks", 4 -> "for", 2 -> "cs")
val result = m1.toList

3.2 可变集合:

// 1. 变长数组
import scala.collection.mutable.ArrayBuffer
val arr = ArrayBuffer[Any](3, 2, 5)
arr.append(4,6,8)     // 增加元素
arr(0) = "白居易"     // 更改元素
arr.remove(0// 删除元素

// 1-2. 变长 / 定长 数组的转换 :arr1.toBuffer  //定长数组 转 可变数组 (返回新的对象, 原对象不变), arr2.toArray  //可变数组 转 定长数组 (返回新的对象, 原对象不变)
val arr = ArrayBuffer[Any](3, 2, 5)
val array = arr.toArray    //转换
val buffer = array.toBuffer   //转换

// 2. 可变list, ListBuffer是可变的list集合,可以添加,删除元素, ListBuffer属于序列
import scala.collection.mutable.ListBuffer
val lb1 = ListBuffer[Int](1, 2, 3)

// 3. 队列
import scala.collection.mutable
val queue = new mutable.Queue[Any]
queue += 1 .  // 添加元素

queue ++= List("a","b") // 把List中的元素拿出来, 一个一个添加, 使用 ++=
val first = queue.dequeue() .  出队列, 从头部取出数据, queue本身会发生变化


 // 4. 可变Map
 val map3 = mutable.Map[String,Any]("a" -> 10, "b" -> 20, "c" -> 30)
 map3("a") = "update" //修改
 map3("A") = "add" //添加
 val map4 = mutable.Map[String,Any]("a" -> 10, "b" -> 20, "c" -> 30)
 map4 += ("e" -> 50, "f" ->60) .  // 添加
 map4 -= ("e", "f")        // 删除

// 5. set += 添加新的元素,可变的支持增删操作
val ms = mutable.Set[Any]()
ms.add(1)
ms += ("a")
ms += 2.0
ms.remove(10) //删除不存在的,不会报错
ms.remove(1)
ms -= 2.0

4. 高阶函数

// 1. map函数
l = List(1,2,3,4,5,6,7,8,9)
l.map(x=> x*2)

// 2. Filter 过滤函数
l.map(_*2).filter(_>8)

// 3. 聚合操作reduce,可以将一个列表中的数据合并为一个
val ar = List(1,2,3,4,5)
println( ar.reduce((x,y)=>x+y))

// 4. flod  相当于给reduceLeft 函数, 在最左边多加了一个 初始值
val ar1 = List(1, 2, 3, 4, 5)
println(ar1.fold(0)(_ + _)) 

// 5. flatmap映射:flat即压扁,压平,扁平化映射 将集合中的每个元素, 一个一个拿出来, 被f函数运算, 将运算后的结果,放到新的集合中返回,如果集合中还有集合, 那么也会拿出来(底层递归操作)
val names = List("Alice", "Bob", "Nick")
val upperName = names.flatMap(upper _)

// 6.获取Scala迭代器的前n个元素的最简单方法
recs.toList.sortWith(_._2>_._2).take(n)

5. 循环

list=Range(0,100)               //左闭右开

for (i <- 1 to|until 5 reverse ) {    
      println("to: " + i)        //左闭右闭    
}
 
// 循环可以控制步长
for(i <- 1 to 3 if i != 2) {
      println("守卫: "+ i )
}

for(i <- 1 to 3; j = 4 - i) {
      println("引入变量: "+ j )   
}

// 循环返回值,但是for循环的返回值必须要关键字 yield上场。如果没有yield,即返回为空
val res3 = for (i <- 1 to 10) yield {
      if (i % 2 == 0) {
        i
      } else {
        "不是偶数"
      }
    }

6. Case| Match 关键字

6.1 scala中的用法

// 1. 可以用作模式匹配
val Pattern1="(s.*)".r
val Pattern2="(kp_max_.*)".r
val v1="spark"
val r= v1 match {
  case Pattern(v1) | Pattern2(_) => "begin s*"
  case "1" => "1"
  case "3" => "3"
  case _ => "default"
}

// 2. 范围匹配
for(x <- 1 to 10){
  val r= x match {
    case x if (x>=0 & x < 5)=> "1-5"
    case x if (x>=5 & x<10) => "5-10"
    case _ => "not found"
  }
}

6.2 spark中case关键字的特殊用法

case 替代map(line=>{})的写法,不在使用._1._2 上一个父rdd的类型值可直接命名为变量使用

val zipped = data.rdd.map((s :Row) => s(0)).zip(tfidf)

val originData = zipped.map{ 
  case (x1 :Int, x2 :Vector) => LabeledPoint(x1, x2) 
  }

// rdd.map(i=>{}) 与 rdd.map{ case ( 上一个rdd的类型值可直接命名为变量使用) =>{ }} 等效

7. 关键字 implicit

7.1 隐式参数

object ScalaImplicit{
  // 隐式参数,隐式参数列表必须放在方法的参数列表后面
  implict val default :Int =50
  def sum(s:Int)(implicit b:Int,c:Int){
    a+b+c
  }
  val res=sum(10)  // 其他两个参数就会默认使用类中的成员变量用implicit修饰的default的值。

7. 2 隐式类

隐式类 所带的构造参数有且只有一个,并且构造器中的参数是转换之前的对象

object ImplicitUnils{
   // 隐式类
  implicit class StringImprovement(val s :Sting){
    def increment=s.map(x => (x+1).toChar)
  }
  
  // 隐式类
  implicit class IntImprovement(val a:Int){
    def square =a* a 
  }
  // 隐式类
  implicit class Ximalaya(val x: Test){
    def getXName=x.getName
  }
}

object Main extendd App {
  import ImplicitUnils._
  println("hello".increment)
  print(2.square)
}

编译器在hello对象调用increment时发现对象上并没有increment方法,此时编译器就会在作用域范围内搜索隐式实体,发现有符合隐式类可以用来转换成有带有increment方法的Stringimprovement类

8. 应用实战

8.1 使用映射集合,统计一句话中,各个字母出现的次数

提示:Map[Char, Int]()

import scala.collection.mutable.ArrayBuffer

object comprehensiveExercise2 {
    def main(args: Array[String]): Unit = {
        val sentence = "abbcccddddeeeee"

        //不可变map实现
        var map = Map[Char, Int]()
        val map2 = sentence.foldLeft(map)(count _)
        println(map2)

        //可变map实现
        val map3 = mutable.Map[Char, Int]()
        sentence.foldLeft(map3)(mutableCount _)
        println(map3)
    }

    //这里用的是不可变的map, 每次返回新的map, 效率相对较低
    def count(map:Map[Char, Int], char: Char):Map[Char, Int]={
        val newMap = map + (char -> (map.getOrElse(char,0) +1) )
        newMap
    }

   //用可变map来实现
    def mutableCount(map:mutable.Map[Char, Int], char: Char) :mutable.Map[Char, Int]={
        map += (char -> (map.getOrElse(char,0) +1) )
    }
}

8.2 集合的合并

两个集合的合并操作,合并后每个元素是一个 对偶元组

object Zip1 {
    def main(args: Array[String]): Unit = {

        //拉链的基本使用-合并
        val list = List("no1", "no2", "no3")
        val list2 = List("北京", "上海", "广州")

        val list3 = list zip list2
        println(list3)

        //结果遍历, 由于是 对偶元祖,所以用 _1, _2 来取值
        for (item <- list3) {
            println("编号=" + item._1 + ", 名字=" + item._2)
        }
    }
}

8.3 迭代器

通过iterator方法从集合获得一个迭代器,通过while和for对集合进行遍历,iterator 的构建实际是 AbstractIterator 的一个匿名子类.


```scala
object Iterator2 {
    def main(args: Array[String]): Unit = {
        val iterator = List(1, 2, 3, 4, 5).iterator //  获取到迭代器 [链表实现]
        println("--------遍历方式1 -----------------")
        while (iterator.hasNext) { // hasNext 方法可以判断是否有下一个
            println(iterator.next()) // next 取出下一个值
        }
        //注意, while遍历完后, 指针已经到了最后,
        //再遍历, 则为空

        println("--------遍历方式2 for -----------------")
        for(enum <- iterator) {
            println(enum) //
        }
    }
}

9. 函数

9.1 函数返回值

  1. 有返回值
 def sum(n1: Int, n2: Int): Int = {
    n1 + n2   //执行到最后一行作为返回值
  }
  1. 只写一个等号, 即:使用类型推导
def arithmeticOpt(n1:Int,n2:Int,opt:Char) = {
    if (opt == '+') {
      n1 + n2
    }else if (opt == '-'){
      n1 - n2
    }else{
      null
    }
  }
  1. 什么也不写, 表示没有返回值
def sumWithNoReturn(n1:Int,n2:Int){
    n1+n2
  }

9.2 函数参数

// 1. 函数没有参数列表的时候, 定义时, 也可以省略()
def test1() ={
    println("这个方法没有形参, 调用时可以不带()")
  }

// 2. 函数体中如果只有一行代码, 则可以省略大括号{}
def test16 = println("函数体中如果只有一行代码, 则可以省略大括号{}")

 // 3. 函数的形参可以为多个
def test2(name:String,age:Int)={
  }
  
// 4. 可变参数
def sum (args: Int*)={
    println("参数个数为: "+args.length)

    var res = 0
    for (elem <- args) {
      res += elem
    }
    println("求和结果为: "+res)
  }

9.3 函数柯里化

函数编程中,接受多个参数的函数, 都可以转化为接受单个参数的函数,这个转化过程就叫柯里化

object Demo1 {
    def main(args: Array[String]): Unit = {
        //编写一个函数,接收两个整数,可以返回两个数的乘积,要求:
        //使用常规的方式完成
        println(mul(10, 10))

        //使用闭包的方式完成
        println(mulCurry(10)(9))

        //使用函数柯里化完成
        println(mulCurry2(10)(8))
    }

    def mul(x: Int, y: Int): Int = x * y
    def mulCurry(x: Int): Int => Int = (y: Int) => x * y
    def mulCurry2(x: Int)(y: Int): Int = x * y
}

10. 类

10.1 构造器

  1. 类有一个主构器和任意数量的辅助构造器,辅助构造器的名称都是this,每个辅助构造器都必须调用一个此前已经定义的辅助构造器或者主构造器。
  2. 多个辅助构造器通过不同参数列表进行区分, 在底层就是构造器重载,
  3. 在Scala的构造器中,你不能调用super(params)
/**
  * 辅助构造器, 必须在第一行调用主构造器
  */
class Person2() {
  var name: String = _
  var age: Int = _

  //构造器1
  def this(name : String) {
    this()  //直接调用主构造器
    this.name = name
  }

  //构造器2
  def this(age : Int) {
    this("匿名") //间接调用主构造器,因为 这里调用构造器1, 构造器1中调用了主构造器!
    this.age = age
  }

  def this(name : String, age : Int) {
    this() //直接调用主构造器
    this.name = name
    this.age = age
  }
}

10.2 继承

//父类
class Base {
  //三种属性
  var n1: Int = 1
  protected var n2: Int = 2
  private var n3: Int = 3

  //方法
  def test100(): Unit = {
    println("base 100")
  }
  protected def test200(): Unit = {
    println("base 200")
  }
  }
}

//子类Sub继承了Base父类
class Sub extends Base {
  //方法
  def sayOk(): Unit = {
    //这里子类中,可以访问到父类的 默认和protected的属性和方法
    this.n1 = 20 // n1_$eq()
    this.n2 = 40 //...
    //this.n3 = 90
    println("范围\t" + this.n1 +"\t"+ this.n2)
    test100()
  }
}

10.3 方法重写

/**
  * scala规定,重写一个非抽象方法需要用override修饰符,
  * 如果想调用 父类中被重写的这个方法,使用super关键字去调用
  */
object OverrideDemo3 {
  def main(args: Array[String]): Unit = {
    val emp = new Emp
    emp.printName()
  }
}

//Person2类
class Person2 {
  var name: String = "tom"
  //父类方法
  def printName()= {
    println("父类 printName() " + name)
  }
}

class Emp extends Person2 {
  //想去重写Person-printName方法,必须显式的声明 override
  override def printName()= {
    println("子类 printName() " + name)
    //如果希望调用父类的printName,则需要使用super.printName()
    super.printName()
  }
}

10.4 实例

/**
  * 练习1
  * 编写computer类, 包含 cpu型号,内存大小,硬盘大小, 等属性, getDetails 方法用于返回这些信息
  *
  * 编写PC子类, 继承computer,添加特有属性: 品牌brand
  * 编写notePad子类, 继承computer,添加特有属性: 颜色color
  *
  * 编写 exercise1, 在main方法中创建pc 和notePad对象, 给对象中所有属性(继承属性+特有属性)赋值,并使用getDetails 方法打印
 
  */
object exercise1 {
    def main(args: Array[String]): Unit = {
        val pc = new PC
        pc.cpu = "core i7"
        pc.memory = 8
        pc.hardDisk = 256
        pc.brand = "lenovo"
        pc.getDetails()
    }

}

class computer {
    var cpu: String = _
    var memory: Int = _
    var hardDisk: Int = _

    def getDetails ()={
        printf("cpu:%s, memory:%d, hardDisk:%d",cpu,memory,hardDisk)
    }
}

class PC extends computer {
    var brand: String = _
    override def getDetails ()={
        printf("cpu:%s, memory:%d, hardDisk:%d, brand:%s",cpu,memory,hardDisk,brand)
    }
}

class NotePad extends computer {
    var color: String = _
}

你可能感兴趣的:(scala,scala,开发语言,后端)