Scala基础笔记

Scala基础

简介

  1. Scala代码都需要通过编译器转换成字节码在java虚拟机上运行,scala可以无缝调用java代码。

  2. Scala 是面向对象的编程语言,同时也是函数式编程。(fp)

  3. 静态类型语言,定义变量时,需要定义类型, 尽管看起来像是动态类型语言。

  4. 在函数式语言中,函数作为一等公民,可以在任何地方定义,在函数内或函数外,可以作为函数的参数和

    返回值,可以对函数进行组合

  5. 提倡定义不变类型val,对值操作的时候不是修改,而是修改新的产生的值,原来的值保持不变。

  6. 提倡使用尾递归。尾递归即只在尾部调用函数本身,没有其他操作。

repl

read- evalutaion -print- loop

在repl模式下有三个模式

paste模式

:pas/:paste

可以粘贴多行代码

slient模式

安静模式,不会输出每个表达式的类型和值

power模式

这个模式并不针对普通用户,并且 cpu 耗费很高,通常用不着

:help

使用帮助

值与变量定义

val 定义后不可变(scala推荐)

var 定义后可以改变

val a:String = "hello scala"

通常不需要定义变量类型,scala会自动推断。

分清不变引用和不变对象

  1. Scala 里所有变量都是指向变量的引用,变量声明为val 意味着它是个不变引用;
  2. 所有方法参数都是不变引用;
  3. 类参数默认是不变引用
  4. 创建可变引用唯一方法是使用var关键字
  5. HashMap 有可变版和不可变版

常用特殊类型

  1. Any(abstract)
    Any 是所有Scala 类型的父类型,定义了通用方法 equals、hashCode、toStirng。Any有两个子类型AnyRef 和 AnyVal
  2. AnyVal 所有值类型,Scala定义类9种非空值类型
  3. AnyRef(class) 所有引用类型的父类,可以看作是java.lang.Object的别名。
  4. 类型匹配 值类型可以按照下图关系进行转换
    类型变换

函数

def + 方法名(参数名 : 参数类型) : 返回类型 = {
  //block内最后一行为返回值

}
  • 当返回值为Unit时可以定义为: def 方法名(参数名 : 参数类型) {}
  • 没有参数的方法可以不带圆括号 例如:“1”.toInt
  • Scala没有静态方法,通过object来实现

单例对象object

单例对象与一个类共享一个名称时,单例对象称为伴生对象,伴生对象与类必须定义在一个源文件中。

变长参数

在参数类型后面加个*

过程(区别过程与函数)

单函数体包含在花括号中,但前面没有等号,那么返回类型就是Unit这样的函 数叫做过程

lazy

单行 val 前面加上lazy 关键字时,它的初始化将被推迟,直到我们首次对它取值。(懒加载)

case class(案例类)

  • 案例类(Case classes)和普通类差不多,非常适合用于不可变数据。
  • 编译器对case类混入了Product特质,编译器对case类增加了copy方法
  • 编译器对case类实现了equals/hashCode/toString等方法
  • 伴生对象中最重要的方法是 unapply 这个方法是在进行构造器模式匹配时的关键。
  • 伴生对象中apply方法则为创建对象提供方便,相当于工厂方法(
  • 伴生对象继承了AbstractFunction,允许接收 Tuple 作为参数构造(即一次性传入多个参数进行构造)
case class A(a: Int, b: Int) 
A.tupled
val t = (100,100)
A.tupled(t)

模式匹配

类似于正则表达式,然后比正则表达式更灵活。

模式

  1. 常量模式

  2. 变量模式

    单纯的变量模式,没有匹配过程,只是单纯的给出了新的变量名

  3. 构造器模式

  4. 通配符模式

  5. 类型模式

    此模式下只能检查包装,不能检查货物

      def main(args: Array[String]): Unit = {
        println(foo(List("STRING")))
      }
      
      def foo(a: Any): String = a match {
        //non-variable type argument String in type pattern List[String] 
        //(the underlying of List[String]) is unchecked since it is eliminated by erasure
        //只能检查包装,检查不了里面的货物一次 下面这行应当这样写List[_]
        case a: List[Int] => "OK"//还是ok
        case _ => "fail"
      }
    
  6. 变量绑定模式

  7. 抽取器模式

  8. 序列模式

  9. 元组模式

option

Scala 里提供了 scala.Option 类,Option 可以看做一个容器要么有东西(Some),要么什么东西都没有

不包含任何值的Option 用None 来构建

包含一个值的Option 用Some 的工厂方法来创建。

数组

Array(100) 和 new Array(100) 有非常大的差别,前者表示实例化一个Array ,Array里面包含一个元素

100,后者 表示实例化一个容量为100 的Array,每一个元素都是Null

定长Array

变长ArrayBuffer

nil:空list

初始化&赋值

val array=new array[Int](7)
#两种赋值方法
array(1)=0
array+=0

遍历打印

array foreach println

数组中对象查找

array.filter(_.arrtibute==xxx)

数组元素处理

(1) :: 该方法被称为cons,意为构造,向队列的头部追加数据,创造新的列表。用法为 x::list,其中x为加入到头部的元素,无论x是列表与否,它都只将成为新生成列表的第一个元素,也就是说新生成的列表长度为list的长度+1(btw, x::list等价于list.::(x))

(2) :+和+: 两者的区别在于:+方法用于在尾部追加元素,+:方法用于在头部追加元素,和::很类似,但是::可以用于pattern match ,而+:则不行. 关于+:和:+,只要记住冒号永远靠近集合类型就OK了。

(3) ++ 该方法用于连接两个集合,list1++list2

(4) ::: 该方法只能用于连接两个List类型的集合

3,4区别是什么?

元素遍历

array.map{
      line =>
        println(s"姓名:${line.name},金额:${line.money}")
    }

基本语法

for

  for(i <- 0 to 3) {
        print(i)
      }//0,1,2,3

      for(i <- 0 until 3) {
        print(i)
      }//0,1,2

 for(i <- 1 to 3; j <- 1 to 3 ){ //if(i != j) 够简略
      println(s"i is $i" + s" j is $j")
    }//双重for循环

要推出循环,不能直接使用break语句,需要加入一个包

import scala.util.control.Breaks._
breakable { var n = 10
for(c <- "Hello World") { if(n == 5) break; print(c)
n -= 1
} }

异常处理

try {
      throw new IndexOutOfBoundsException("....")
    } catch {
      case e: IndexOutOfBoundsException => e.printStackTrace()
    }

文件读取

val root = ReadFileDemo.getClass.getResource("/")
val url = new URI(root + "readMe.txt");
//    val f = new File(),所以需要构造URL
    //注意 fromFile 接收的参数是URI
    lazy val words = scala.io.Source.fromFile(url).mkString

    //定义lazy 变量的作用是延迟加载,用到变量的时候才去加载
    println(words)

Option

Option[T] 是一个类型为 T 的可选值的容器: 如果值存在, Option[T] 就是一个 Some[T] ,如果不存在, Option[T] 就是对象 None

getOrElse(parameter)

有就输出,没有就输出parameter(默认值)

extractor

 def extractorMM(it: Student) = it match {
    case Student("李磊",age) => println(age)
    case  _ => println("none")
  }
object Square {
  //unapply方法通常被称为提取方法,这里提取的是一个容器,里面有z的开方
  //Option 是一种容器,有两个子类Some 和 None 要么有值,要么啥都没有
  def unapply(z: Double): Option[Double] = Some(math.sqrt(z))
}

object SquareTestor{
  def main(args: Array[String]) {
    val number = 7.0
//    println(Square.unapply(number))//传统方式调用
//    这样我们无需显式调用unapply方法,而把是它用在pattern match中,让编译器替我们调用它。
    number match {
        //通过StringContext 方法拼接字符串
      case Square(n) => println(s"square root of $number is $n")#符合函数条件
      case _=>  println("nothing matched")
    }
  }

}

函数

模版

def function(parameter:dataType):returnType={
returnParameter
}

模式匹配

def main(args: Array[String]): Unit = {
    println(foo(List("STRING")))
  }
  
  def foo(a: Any): String = a match {
    //non-variable type argument String in type pattern List[String] 
    //(the underlying of List[String]) is unchecked since it is eliminated by erasure
    //只能检查包装,检查不了里面的货物一次 下面这行应当这样写List[_]
    case a: List[Int] => "OK"//只检测是List
    case _ => "fail"
  }

变量绑定

匹配成功后把值绑定给变量

 def main(args: Array[String]) {
    val tree = Tree(TreeNode("root",TreeNode("left", null, null),TreeNode("right", null, null)))
    println(tree.root match {
      case TreeNode(_, leftNode_var@TreeNode("left",_,_), _) => leftNode_var
      //依然是上面的TreeNode,如果我们希望匹配到左边节点值为”left”就返回这个节点的话:
      //即是匹配到了上面的treenode,然后把形如@TreeNode("left",_,_)的treenode绑定给leftnode_var
      //然后返回
      case _ => println("error")
    })
  }
发布了36 篇原创文章 · 获赞 8 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_42297075/article/details/104126023