Scala语言学习

Scala语言学习

基础

  • 安装Scala
  • REPL(Read-Evaluate-Print-Loop shell)
  • 处理数据
    • 字面量:直接出现在源代码中的数据
    • valueval [: ] =
      • 不可变的、有类型的存储单元,支持类型推导
    • 变量variablevar [: ] =
      • 可变的、有类型的存储单元,支持类型推导
      • 可重新赋值,但是不可改变数据类型(支持类型转换的例外)
    • 命名:支持使用字母、数字和一些特殊的操作符字符
      • 例如可以使用等,不能使用[].

      • 合法命名规则

        • 不以数字开头
          • 以数字开头的话,编译器最初会把解析到的第一个数字当成一个字面量数字,然后后面解析到其他非数字字符就会出错
        • 一个或多个除反引用号外的任意字符,这些字符必须包围在一对反引号之中
        val `a.b` = 4
        
  • 类型
    • 核心数值类型

      • ByteShortIntLongFloatDouble
      • toType方法手动完成类型间转换
      • JVM包装数值类型可以互操作
    • 字符串String

      • 建立在JavaString基础上

      • Java不同,==会检查字符串真正的想等性,而不是对象引用想等性

      • 三重引号创建多行String,类似Python """ your string """

      • 字符串内插

        • 在字符串的第一个双引号前面增加一个s前缀,使用美元符$指示插入数据的引用(某些容易区分的情况下,大括号{}可以省略,但是加上更容易区分)
        val approx = 355/113f
        println(s"Pi, using 355/133, is about ${approx}.")
        
      • 字符串内插的替代格式可以使用printf语法(java.util.Formatter

        • 在字符串前面添加f前缀
        scala> val item = "apple"
        scala> f"Enjoying this $item ${355/133.0}%.5f times today.")
        
      • 正则表达式(基于Javajava.util.regex.Pattern

        • 用正则表达式捕获值val () = )
        • val pattern = """.* apple ([\d.]+) times .*""".r
        • val pattern(amountText) = input
        • val amount = amountText.toDouble
    • Scala类型概述

      Scala类型概述

      • Nothing:所有类型的子类
      • Null:所有指示null值的AnyRef类型的子类
      • Unit:指示没有值(类似void
      • AnyScala中所有类型的根
      • AnyVal:所有值类型的根
      • AnyRef:所有引用(非值)类型的根
    • Scala不支持其他类型到Boolean类型的自动转换。非null字符串不会计算为true

    • 元组 (,[,...])

      • 不同于列表和数组,没有办法迭代处理一个元组中的元素,元组的作用只是作为多个值的容器
      • 根据元素的索引访问元组中的元素(下划线加上索引,索引从1开始)
      • 创建一个大小为2的元组,也可以使用关系操作符(->),表示元组中的键值对

表达式和条件式

  • 表达式块(用{}结合多个表达式创建,最后一个表达式作为表达式块的返回值)

    • 可嵌套、跨行,多个表达式写在一行需要;分隔
  • 语句:不返回值的表达式

  • if...else表达式块

    • if ()
    • if () else
  • 匹配表达式(类似switch

    • Scala匹配表达式支持匹配如值、类型、正则表达式、数值范围和数据结构内容
     match{
        case  => 
        [case ...]
    }
    
    • 可以使用模式替换式(pattern alternative),匹配多种内容
    • case | .. =>
    • 增加通配模式,放止输入内容无法匹配的情况运行时异常
      • 值绑定模式case =>
        • 将输入绑定到一个特定的字面量上,如果不匹配就会进入这个绑定值的情况
      • 使用通配符 _:相当于匿名占位符,将在运行时替换为一个表达式的值
        • 与值绑定的不同在于不能再case表达式块中访问通配符的值
    • 用模式哨位匹配
      • 增加一个if语句,为匹配表达式增加条件逻辑
      • case if =>
    • 用模式变量匹配类型
      • 匹配输入表达式的类型
      • case : =>
  • 循环

    • Range(范围)数据结构

      • [to|until] [by increment]
    • 基本for循环迭代处理

      • for ( <- ) [yield] []
      • yield:如果指定,则调用的所有表达式的返回值将作为一个集合返回,如果没有指定,则调用表达式,但是不能访问它的返回值
      • for (x <- 1 to 7){println(s"Day $x:")}
    • 迭代器哨位(过滤器)

      • for ( <- if )...
      • threes = for(i <- 1 to 20 if i%3 == 0) yield i
    • 嵌套迭代器

      for{ x <- 1 to 2
           y <- 1 to 3 }
         { print(s"($x,$y) ")}
      
    • 值绑定

      • for ( <- ; = )...
      • for(i <- 0 to 8; pow = 1 <
    • WhileDo/While循环

      • while() statement

函数

  • 定义无输入的函数
    • def =
    • def () =
    • 如果定义函数时没加小括号,则调用时也不可以加小括号,而加了小括号的无输入函数调用时可以不加小括号
  • 定义函数时指定返回类型 def : =
  • 定义函数 def (: [,...]): =
  • 过程:没有返回值的函数
  • 使用表达式块调用函数
    • 当使用一个参数调用函数时,可以使用表达式块返回的结果发送参数
  • 递归函数
    • 递归函数可能会遇到“栈溢出”错误,Scala编译器可以使用尾递归优化一些递归函数
    • 利用尾递归优化的函数,递归调用不会创建新的空间,而是使用当前函数的栈空间
    • 只有最后一个语句是递归调用的函数才能由Scala编译器完成尾递归优化
    • 可以利用函数注解来标志一个函数将完成尾递归优化@annotation.tailrec
  • 嵌套函数
  • 用命名参数调用函数
    • 可以不按原先定义的顺序指定参数
  • 有默认值的参数
  • Vararg参数
    • 这是一个函数参数,可以匹配调用者的0个或多个实参
    • vararg参数后面不能跟非vararg参数,因为无法加以区分
    • vararg参数实现为一个集合,可以通过迭代器访问
    • 要标志一个参数匹配一个或者多个输入实参,在函数定义中需要该参数类型后面增加一个*
    • 例如def sum(items: Int*): Int = {...}
  • 参数组
    • 可以把参数表分解为参数组,每个参数组用小括号分割
    • 例如def max(x:Int)(y:Int) = if (x > y) x else y
  • 类型参数
    • 类型参数指示了值参数类型或返回值类型
    • 函数参数或返回值的类型不再固定,而是可以由函数调用者设置
    • def [type-name](:): ...
    • 例如def identity[A](a: A): A = a
  • 方法和操作符
    • 中缀点记法:.[()]
    • Scala中使用的所有算术运算符都是方法
    • Scala的操作符记法允许使用空格分隔对象、操作符方法和方法的参数(只有一个)
    • 例如2 + 32.+(3)是一样的
    • 操作符记法:
      • 如果要调用多个参数,则必须将多个参数包含在()

      首类函数

      • “首类”表示函数不仅能得到声明和调用,还可以作为一个数据结构用在这个语言的任何地方
      • 高阶函数:接受其他函数作为参数,或者使用函数作为返回值
      • 声明式编程:要求使用高阶函数或其他机制声明要做的工作,而不手动实现
      • 命令式编程:总要明确指定操作的逻辑流
      • 函数类型和值
        • 函数的类型是其输入类型返回值类型的一个简单组合,用一个箭头从输入类型指向输出类型

        • ([, ...]) =>

          def double(x: Int): Int = x*2
          val myDouble: (Int) => Int = double
          val myDoubleCopy = myDouble
          val myDouble2 = double _
          
          • myDouble就是一个值,只不过这个值可以调用
          • 一个函数值可以赋值给一个新值
          • myDouble必须有显示的类型,以区分它是一个函数值,而不是一个函数调用(如果函数只有单个参数可以省略小括号)
          • val = _:使用通配符为函数赋值
      • 函数字面量
        • 创建一个没有名字的函数并把这个函数赋值一个新的函数值
        • val doubler = (x: Int) => x * 2
        • 函数字面量是所赋数据的一个字面量表达式
        • 其他名字:匿名函数Lambda表达式Lambdasfunction0,function1,function2,...(Scala编译器对字面量的叫法。根据输入参数的个数而定,单参数就叫)
        • 语法:([: , ...]) =>
      • 占位符语法
        • 函数字面量的一种缩写形式,将命名参数替换为通配符(_

        • 使用条件

          • 函数的现实类型在字面量之外指定(明确好输入输出)
          • 输入参数最多只使用一次(因为只能按照位置匹配一次,多个占位符有着相同的符号,匹配之后就无法确定需要的参数)
        • 示例

          def combination(x: Int, y: Int, f: (Int,Int) => Int) = f(x,y)
          combination(23, 12, _*_)
          
          def tripleOp[A,B](a: A, b: A, c: A, f: (A, A, A) => B) => f(a, b, c)
          tripleOp[Int, Int](23, 92, 14, _ * _ + _)
          tripleOp[Int, Double](23, 92, 14, 1.0 * _ / _ / _)
          
      • 部分应用函数和柯里化
        • 功能:为函数保留一些重复使用的参数

        • 方法一:部分应用(partially apply)函数,使用通配符替代其他参数(函数按位置匹配)

          def factorOf(x: Int, y: Int) = y % x == 0
          val mutipleOf3 = factorOf(3, _: Int)
          val y = mutipleOf3(78)
          
        • 方法二:函数柯里化(curring,讨好的意思),使用参数组

          • 有多个参数表的函数可以认为是多个函数的一个链。单个参数表则认为是一个单独的函数调用

            def factorOf(x: Int)(y: Int) = y % x == 0
            val isEven = factorOf(2) _
            val z = isEven(32) // z = true
            
          • def factorOf(x: Int)(y: Int)的函数类型为 Int => Int => Boolean

      • 传名参数
        • 一种函数参数类型:可以取一个值,也可以取最终返回一个值的函数

        • 语法:: =>

          scala> def doubles(x: => Int) = {
               |     println("Now doubling" + x)
               |     x * 2
               | }
          doubles: (x: => Int)Int
          
          scala> doubles(5)
          Now doubling 5
          res1: Int = 10
          
          scala> def f(i: Int) = { println(s"Hello from f($i)"); i }
          f: (i: Int)Int
          
          scala> doubles( f(8) )
          Hello from f(8)
          Now doubling 8
          Hello from f(8) //doubles调用两次x,所以f函数也调用两次
          res2: Int = 16    
          
      • 偏函数
        • 有些函数并不能支持满足输入类型的所有可能值。这种函数称为偏函数,因为它们只能部分应用于输入数据
      • 用函数字面量块调用高阶函数
        • 实际上就是输入的参数类型是函数,那个输入参数可以用表达式块或者函数字面量来代替
        • 好处
          • 将单独的代码块包为在工具函数中
          • 管理数据库事务,即高阶函数打开会话,调用函数参数,然后commit或者rollback结束事务
          • 重新尝试处理可能的错误,将函数参数调用指定的次数,直到不再产生错误
          • 根据局部、全局或者外部值有条件地调用函数参数

      常用集合

      • 列表、集和映射
        • List:不可变的单链表
          • 访问列表中的单个元素,可以作为一个函数调用这个列表,并提供一个索引号(从0开始)
          • List是一个不可变的递归数据结构(链表),列表中的每一项都有自己的表头和越来越短的表尾
          • 所有列表都有一个Nil实例作为终结点,可以通过比较当前元素与Nil来检查是否到达列表表尾(Nil实际上是List[Nothing]的一个单例实例
        • Set:不可变的无序集合
        • Map:不可变的键值库,也称为散列映射、字典或关联数组
        • ListSetMap的根类型都是Iterable
          • foreach():取一个函数,对列表中的每一项,分别调用这个函数
          • map():取一个函数,将一个列表元素转换为另一个值或类型
          • reduce():取一个函数,将两个列表元素结合为一个元素
      • Cons操作符
        • 可以通过consconstruct的简写)操作符来构建列表

        • 使用Nil为基础,并使用右结合的cons操作符::绑定元素,就可以构建列表

          val numbersOld = List(1,2,3)
          val numbers = 1 :: 2 :: 3 :: Nil
          
        • ::List的一个方法,它取一个值,这会成为新列表的表头

          val first = Nil.::(1) // 1 -> Nil
          
      • 列表算术运算
        • 因为List是一个不可变的集合,所有“修改”是指“返回一个新列表,其中包含所请求的修改”
        • 谓词函数(predicate function):得到一个输入值后会相应地返回truefalse
        • :::为列表追加单个元素
        • ::::为列表追加另一个列表
        • ++:为列表追加另一个集合
        • ==:判断集合类型和元素内容是否相同
        • distinct:返回不包含重复的列表
        • drop:去除列表前n个元素
        • filter:输入一个谓词函数,过滤掉指定的元素
        • flatten:将一个包含列表的列表转换为元素列表
        • partition:输入一个谓词函数,将元素分组,由两个列表组成一个元组
        • reverse:逆转列表
        • slice:切片,输入切片的开头和结尾,输出不包括结尾
        • sortBy:根据指定函数排序
        • sorted:根据自然顺序排序
        • splitAt:根据指定索引将列表切分成两个
        • take:从列表抽取前n个元素
        • zip:两个列表合并为一个元组列表
      • 映射列表
        • collect:使用偏函数转换各个元素,保留可应用的元素
        • flatMap:给定一个函数转换各个元素,扁平化结果(消除列表中的列表,这种嵌套结构)
        • map:使用给定函数转换各个元素
        • Scala可以把Java数组转换为它自己的类型Array
      • 归约列表
        • 将列表收缩为单个值
        • Scala的集合支持:
          • 数学归约:maxminproductsum
          • 逻辑归约:containsendsWithexistsforallstartsWith
          • 通用的高阶操作,折叠,可以用来创建任何其他类型的列表归约算法
            • foldfoldLeftfoldRightreducereduceLeftreduceRightscanscanLeftscanRight
      • 转换集合
        • mkString:根据指定分隔符将一个集合转换为String
        • toBuffer:将一个不可变的集合转变为可变的集合
        • toList:将一个集合转变为List
        • toMap:将一个2元元组的集合转换为一个Map
        • toSet:将一个集合转换为一个Set
        • toString:将一个集合呈现为一个String,包括集合的类型
      • JavaScala集合兼容性
        • 默认情况下两者集合类型是不兼容的
        • 添加JavaConvertersimport collection.JavaConverters._
        • 集合转换:asJavaasScala
      • 使用集合的模式匹配
        • 匹配表达式、模式哨卫、值绑定
        • 模式匹配是Scala语言的一个核心特性

      更多集合

      • 可变的集合类型 : 不可变的集合类型

        • collection.mutable.Buffer : collection.imutable.List
        • collection.mutable.Set : collection.imutable.Set
        • collection.mutable.Map : collection.imutable.Map
        • 使用toListtoSettoMap将可变集合类型转换回不可变的集合类型
      • 从不可变集合创建可变集合

        • 不可变集合ListMapSet都可以使用toBuffer方法转换为可变的collection.mutable.Buffer类型
      • 使用集合构建器

        • Builder:生成指定的集合类型,只支持追加操作
        • Set.newBuilder[Char]
        • 需要调用result方法得到最终结果
      • 数组

        • Array是一个大小固定的可变索引集合,实际只是Java数组类型的一个包装器,另外还提供了隐含类高级特性,使它可以项序列一样使用
        • val numbers = Array(1, 2, 3, 4)
      • Seq和序列

        • Seq是所有序列的根类型

          序列集合层次体系

        • Seq:所有序列的根类型,List()的快捷方式

        • IndexedSeq:索引序列的根类型,Vector()的快捷方式

        • Vector:这一类列表有一个后备Array实例,可以按索引访问

        • Range:整数范围。动态生成数据

        • LinearSeq:线性(链表)序列的根类型

        • List:元素的单链表

        • Queue:先进先出列表

        • Stack:后进先出列表

        • Stream:懒列表。访问元素时才增加相应元素

        • String:字符集合,扩展了Iterable

      • Stream

        • 懒集合,由一个或多个启示元素和一个递归函数生成。流可能是无界的,理论上是无限的集合,只是在访问元素时才回生成这个元素

        • 使用Stream.cons用表头表尾构建一个新的流,替代语法,可以使用#::操作符

        • 示例:def inc(head: Int): Stream[Int] = head #:: inc(head+1)

        • 创建一个有界的流

          def to(head: Char, end: Char): Stream[Char] = (head > end) match {
              case true => Stream.empty
              case false => head #:: to((head+1).toChar, end)
          }
          
      • 一元集合

        • 支持类似Iterable中的变换操作,但是包含的元素不能多于1个
      • Option集合

        • 扩展了Iterable的一个一元集合,Option类型表示一个值的存在或不存在
        • Option可以安全地替代null值,告诉用户这个值可能不存在,从而减少出发NullPointerException异常的可能性
        • 另一些开发人员把它看作是构建操作链的一种更为安全的方法,确保操作链中只包含有效的值
        • Option依赖两个子类型提供的具体实现:SomeNone
          • Some:一个类型参数化的单元素集合
          • None:一个空集合。None类型没有类型参数,因为它永远不包含任何内容
          • isDefinedisEmpty分别检查一个给定的OptionSome还是None
        • Option集合提供了一种安全的机制,而且还提供了一些操作来存储和变换可能存在也可能不存在的值,还提供了一些安全操作可以抽取可能存在的值
        • 警告:避免使用Option.get(),此方法不安全,对None调用get()将导致运行时错误
        • 安全的Option抽取操作
          • fold
          • getOrElse:为Some,则返回值;为None,则返回传名参数的结果
          • orElse:非空,返回这个Option,否则从给定的传名参数返回一个Option
          • 匹配表达式 match{ case Some(x) => x; case None => -1 }
      • Try集合

        • 将错误处理转变为集合管理。提供一种机制来捕获给定函数参数中发生的错误,并返回这个错误。
        • Scala抛出一个异常会中断程序流,并把控制交回给最近的处理器来处理这个特定的异常。未处理的异常会终止应用。
        • Scala支持try{}..catch{}块。
        • 推荐使用util.Try(),因为它提供了一种更安全、更有表述性,而且纯粹一元的方法来处理错误
        • util.Try类型没有具体实现,但是有两个已实现的子类型SuccessFailure
        • 使用Try的错误处理方法
          • flatMap:对于Success,调用一个同样返回util.Try的函数,从而将当前返回值映射到一个新的内嵌返回值

          • foreach:一旦Success,执行给定的函数,Failure则什么都不做

          • getOrElse:返回Success中的内嵌值,对于Failure则返回传名参数的值

          • orElse:与flatMap相反。对于Failure,调用一个同样返回util.Try的函数

          • toOption:将util.Try转换为Option,缺点是丢失内嵌的Exception

          • map:对于Success,调用一个函数,将内嵌值映射到一个新值

          • 匹配表达式 match { case util.Success(x) =>x; case util.Failure(error) => -1 }

          • 什么都不做:只需要允许异常在调用栈中向上传播,直到被捕获或者导致当前应用退出

            val input = " 123 "
            val result = util.Try(input.toInt) orElse util.Try(input.trim.toInt)
            result foreach { r => println(s"Parsed '$input' to $r!") }
            val x = result match {
                case util.Success(x) => Some(x)
                case util.Failure(ex) => {
                    println(s"Couldn't parse input '$input'")
                    None
                }
            }
            
      • Future集合

        • concurrent.Future,发起一个后台任务
        • future表示一个可能的值,并提供了安全操作来串链其他操作或者抽取值。与OptionTry不同,future的值不是立即可用,因为创建future时后台任务可能仍在工作。
        • 支持在并发线程中运行后台任务。
        • 调用future并提供一个函数会在一个单独的线程中执行该函数,而当前线程仍继续操作
        • 在创建future之前,必须指定当前会话或应用的“上下文”来并发运行函数,默认使用global上下文
          • import concurrent.ExecutionContext.Implicits.global
        • 可以设置回调函数或另外的future,当future任务执行完成时,执行这个回调或者future
        • 异步处理future
          • fallbackTo:将第二个future串链到第一个future,如果第一个future不成功,则调用第二个future
          • flatMap:如果第一个成功,则使用第一个的返回值调用第二个future
          • map:将给定的函数串链到future,如果future成功,则其返回值将用来调用这个函数
          • onCompletefuture任务完成后,将用一个util.Try调用指定函数,其中包含一个值(成功)或者一个异常(失败)
          • onFailure:如果future任务抛出一个异常,将使用这个异常来调用指定函数
          • onSuccess:如果future任务成功完成,将使用返回值来调用给定函数
          • Future.sequence:并发地运行给定序列中的future,返回一个新的future
        • 同步处理future
          • concurrent.Await.result(),取后台线程和一个最大等待时间
          • 等待时间:import concurrent.duration._
          • 等待10s:val maxTime = Duration(10, SECONDS)

      • 基础

        • Scala中,类参数在类名后指定,就像函数定义中函数参数跟在函数名后面一样。类参数可以用来初始化字段(类中的值和变量),或者用于传入函数,但是一旦类已经创建,这些参数就不再可用
        • 可以把某个字段声明为类参数,通过在类参数前增加val或者var,类参数就成为类中的一个字段
        • Scala中,一个类可以使用extends关键字扩展最多一个其他类,另外可以用override关键字覆盖所继承方法的行为
        • 类中的字段和方法用this关键字访问,父类中的字段和方法可以用super关键字访问
        • Scala多态指类能够采用其他兼容类的形式。“兼容”指一个子类的实例可以用于替代其父类的实例,但是反过来不行
      • 定义类

        class   [type-parameters]
                            [([val|var] : [, ...])] //输入参数可以有默认值
                            [extends [type-parameters]()] //继承父类可以有输入参数
                            [{ fields, methods, and classes }]
        
        • 实例就是一个内存分配,提供了类字段的存储空间。这个动作(即预留空间来分配一个类的内容)称为实例化
        • 访问类的字段和方法:标准中缀点记法、中缀操作符记法
      • 抽象类

        • 将由其他类扩展的一个类,而自己不能实例化
        • abstract关键字指定
        • 定义其子类必须有的核心字段和方法,但一般不提供具体实现(可以有默认实现)
        • 基于多态,如果一个值的类型为抽象类,它可以具体指向某个非抽象子类的实例,调用方法时实际上最后会在子类上调用
      • 重载方法

      • apply方法

        • 名为“apply”的方法有时是指它要作为一个默认方法或一个注入方法,可以直接调用而不需要方法名
        • 实际是一种快捷方式,可以使用小括号触发功能而不需要方法名,就如python__call__方法,以及pytorchforward
      • 懒值

        • 定义一个值时可以在val关键字前面加上关键字lazy来创建一个懒值
        • 类中使用的字段(值和变量)都是在类第一次实例化时创建的,而懒值是第一次调用时创建
        • 要确保时间或者性能敏感操作在类的生命周期中只执行一次,懒值则是一种很好的方法
        • 常用于存储基于文件的属性、打开的数据库链接,以及其他只有在确实必要时才初始化的不可变数据等信息。
      • 包装

        • Scala文件定义包:package
        • 源文件要存储在与包匹配的目录中
        • 访问包装类:用点分隔的包路径或者导入包
        • Java不同,代码中的任何位置都可以使用import,与python类似
        • 支持使用_操作符导入一个包的全部内容
        • 导入组:import .{[,...]}
        • 使用导入别名:import .{ => }
        • 包装语法:包作为一个块,用大括号包围它的类 package { }
      • 私密性控制

        • 默认地,Scala不会增加私密性控制
        • protected:同一个类或者子类中的代码才能访问
        • private:仅定义这个字段或方法的类可以访问
      • 私密性访问修饰符

        • 包级保护
          • 另外,可以根据另一个类的亲密性覆盖这些策略
        • 实例级保护
      • 最终类和密封类

        • final类不能在子类中被覆盖,final关键字定义的值,变量或方法,可以确保所有子类都将使用这个实现
        • sealed密封类
          • 密封类会限制一个类的子类必须位于福勒所在的同一个文件中

      对象、Case类和Trait

      • 对象object
        • 一种类类型,只能有不超过1个实例,也就是单例(singleton
        • Java和其他语言的某些字段和方法为“静态”或“全局”,对象可以提供类似的功能,不过将它们与可实例化的类解耦合
        • 对象不是用new关键字创建,只需要按名字直接访问,在首次访问时自动实例化(第一次访问前,不会实例化)
        • 定义对象用object关键字,没有任何输入参数,对象不能扩展,但是别的类可以继承它
        • 定义:object [extends ] [{ fields, methods, and classes }]
        • 最适合object的函数是纯函数和处理外部I/O的函数
          • 纯函数:会返回完全由其输入计算得到的结果,而没有任何副作用
          • I/O函数:处理外部数据的函数,如处理文件、数据库和外部服务
        • apply方法和伴生对象
          • 工厂模式是一种很流行的方法,可以从伴生对象生成一个类的新实例。

          • 伴生对象是与类同名的一个对象,与类在同一个文件中定义

            class Multiplier(val x: Int) { def product(y: Int) = x * y }
            object Multiplier { def apply(x: Int) = new Multiplier(x) }
            
        • 使用对象的命令行应用
          • 使用对象中的一个main方法作为应用的入口点
          • def main(args: Array[String]) { ... }
        • Case
          case class  ([var] : [,...])
                                   [extends ()]
                                   [{ fields and methods }]
          
          • 不可实例化的类,包含多个自动生成的方法,包括一个自动生成的伴生对象
          • 适合数据传输对象,主要用于存储数据
          • val关键字可以用,但是case类默认将输入参数转换为值字段,所以没必要添加,如果需要一个变量字段,则使用var关键字
          • case类方法
            • apply:对象object中,一个工厂方法,用于实例化case
            • copy:类中,返回实例的一个副本
            • equals:类中
            • hashCode:类中
            • toString:类中
            • unapply:对象中,将实例抽取到一个字段元组,从而可以使用case类实例完成模式匹配
        • Trait
          • trait不能实例化,支持多重继承的类
          • trait不能有类参数,但可以有类型参数
          • 定义:trait [extends ] [{ fields, methods, and classes }]
          • 用with关键字为类增加一个或多个trait,类没有扩展trait,而是被trait扩展,trait为现有的类增加新的功能或者配置,这个特性也称为依赖注入
            • Spring通过定制Java注解和初始化模块实现了类似的功能,但是Scalatrait不要求特定的注解或特殊的包来实现依赖注入
        • 导入实例成员
          • 与导入类和对象的import使用方法一样,可以导入单个成员,或者通过通配符_导入所有成员
          • 不会覆盖私密性控制,只能导入可以正常访问的字段和方法

      高级类型

      • 暂略

      你可能感兴趣的:(Scala语言学习)