• Scala学习笔记-6-其他


    返回值类型可以不指定,建议指定

    Trait 特质

    • Traits 封装了方法和变量,和 Interface 相比,它的方法可以有实现,这一点有点和抽象类定义类似;
    • Scala 中类继承为单一继承,但是可以和多个 Trait 混合,这些 Trait 定义的成员变量和方法也就变成了该类的成员变量和方法;
    • 创建类的时候可以使用 extends 或 with 来混合一个 trait;
    • Traits 也算是继承制的父类,所以可以用 Traits 引用来接收子类对象(多态)
    • Trait 不能有任何“类”参数
    • Ordered Trait,一个用于对象之间进行比较的 Trait(类似 Java 的 Comparable 接口),只需要复写 compare 方法:=0,表示两个对象相同,>0表示前面大于后面对象,<0表示前面小于后面对象
    package test
    
    object MyTest extends Super {
      override def main(args: Array[String]): Unit = {
        val t: Test = new MyTest(1)
        t.hello()
        println(new MyTest(1) > new MyTest(100))
      }
    }
    
    trait Test {
      def hello(): Unit = println("hello scala")
    }
    
    class MyTest(i: Int) extends AnyRef with Test with Ordered[MyTest]{
      val value: Int = i
      override def compare(that: MyTest): Int = this.value - that.value
    }
    
    • Trait 用来实现可叠加的修改操作。
    package test
    
    object MyTest extends Super {
      override def main(args: Array[String]): Unit = {
        // 创建对象的时候再进行混合(这里也支持多个with混合)
        val t = new MyTest(1) with Test
        t.hello()
      }
    }
    
    // 定义一个抽象类
    abstract class Base {
      def hello(): Unit
    }
    
    // 这里继承了抽象类 Base,则该 trait 只能与实现了同样抽象类的子类混合
    trait Test extends Base {
      // 注意这里的修饰符 abstract override,这是必须的
      abstract override def hello(): Unit = {
        // 这里可以调用super(在普通类中这样是不行的),这里虽然父类中的方法是抽象的,但是这里其实是动态绑定
        super.hello()
        println("==OVER==")
      }
    }
    
    class MyTest(i: Int) extends Base {
      val value: Int = i
    
      override def hello(): Unit = {
        println(s"my value is ${this.i}")
      }
    }
    

    Package

    // 类似Java的写法
    package bobsrockets.navigation
    class Navigator
    
    // 类似C#的写法
    package bobsrockets.navigation {
      class Navigator 
    }
    
    • 支持嵌套
    package bobsrockets{
      package navigation{
        class Navigator{
          // 访问同一包中定义的类型,无需使用前缀,直接使用类型的名称即可访问
          var map =new StarMap   
        }
        class StarMap
      }
    
      class Ship {
        // 嵌套的 package 也可以在其父包中被同级别的其它类型直接访问,而无需使用全称(公共的包不用带,内部包名还是要带的)
        val nav= new navigation.Navigator
      }
    
      class fleets{
        class Fleet{
          // 内层的类型可以直接访问其外层定义的类型
          def addShip() {new Ship}
        }
      }
    }
    
    • 复杂嵌套下的访问
    package launch{
      class Booster3
    }
    package bobsrockets{
      package navigtion{
        package launch{
          class Booster1
      }
      class MissionControl{
        val booster1 =new launch.Booster1
        val booster2=new bobsrockets.launch.Booster2
        // Scala 提供了_root_,也就是所有最外层的类型都可以当成定义在_root_包中
        val booster3=new _root_.launch.Booster3
       }
      }
      package launch{
        class Booster2
      }
    }
    

    import

    • Scala 使用“_” 而非”*”作为通配符;
    • 可以出现在文件中任何地方
    • 可以 import 对象(singleton 或者普通对象)和 package 本身
    • 支持对引入的对象重命名或者隐藏某些类型
    // 导入具体某个类
    import bobsdelights.Fruit
    
    // 导入包下的所有类
    import bobsdelights._
    
    // 类似Java中的静态导入,可以直接使用 Fruits 中定义的对象
    import bobsdelights.Fruits._
    
    // 直接导入包,使用的时候用包名.类名的方式
    import java.util.regex
    
    // 仅导入Apple和Orange,隐藏其他类型
    import Fruits.{Apple, Orange}
    
    // 导入的同时重命名
    import Fruits.{Apple => MaIntosh, Orange}
    
    // 导入的包也可以重命名
    import java.{sql => S}
    
    // 隐藏掉Apple,导入其他所有
    import Fruits.{Apple => _, _}
    
    // 隐含的导入;后导入的会覆盖前导入的;Predef 为一对象(非报名),因此可以直接使用 Predef 对象定义的方法(静态引用);
    import java.lang._
    import scala._
    import Predef._
    

    访问控制

    • 私有成员
    class Outer{
      class Inner{
        private def f(){
          println("f")
        }
        class InnerMost{
          f() //OK
        }
      }
      // 这里Java中是可以的,但是Scala中不可以。Java 允许外部类型访问其包含的嵌套类型的私有成员,
      (new Inner).f();
    }
    
    • 保护成员
      在 Scala 中,由 Protected 定义的成员只能由定义该成员和其派生类型访问。
      在 Java 中,由 Protected 定义的成员可以由同一个包中的其它类型访问。
    class p{
      class Super{
        protected def f() {
          println("f")
        }
      }
      class Sub extends Super{
        f()
      }
      class Other{
        (new Super).f() //error: f is not accessible
      }
    }
    
    • 公开成员
      public 访问控制为 Scala 定义的缺省方式,不用写(根本就没这个关键字)

    为访问控制修饰符添加作用域

    private[x]或protected[x]
    其中 x 代表某个包,类或者对象,表示可以访问这个 Private 或的 protected 的范围直到 X。

    包对象

    • 定义在package.scala文件中,格式如下
    • 包中除了可以定义类、Trait、Object,还可以定义函数、变量
    • 每个包只有一个包对象,任何放在包对象的类型都可以认为是包自身的成员。
    package object test {
      def show(): Unit = println("i am test")
    }
    
    // 包对象也可以导入,然后调用
    import test.show
    

    Scala之偏函数Partial Function 与 case语句

    https://blog.csdn.net/bluishglc/article/details/50995939

    case与匿名函数

    // 完整写法
    List(1, 2 ,3 ,4 ,5).map((i: Int) => i * i)
    
    // 使用case语句构造匿名函数
    List(1, 2 ,3 ,4 ,5) map {
      case i => i * i
    }
    
    // case可以省略掉
    List(1, 2 ,3 ,4 ,5) map {
      i => i * i
    }
    

    case与偏函数

    val f1 = Future { Random.nextInt(10000) }
    
    // 偏函数
    val f2 = f1.andThen(new PartialFunction[Try[Int], Unit] {
      override def isDefinedAt(x: Try[Int]): Boolean = x.isSuccess
      override def apply(v1: Try[Int]): Unit = println(s"do something...  ${v1.get}")
    })
    
    f2 onComplete {
      case Success(value) => println(value)
      case Failure(exception) => println("ERR>>>", exception.getMessage)
    }
    
    // 使用case语句构造偏函数
    val f3 = f1.andThen({
      case v1 => println(s"do something...  ${v1.get}")
    })
    
    f3 onComplete {
      case Success(value) => println(value)
      case Failure(exception) => println("ERR>>>", exception.getMessage)
    }
    

    Scala之Future和Promise

    参考:Future和Promise

    基本使用

    implicit val ec: ExecutionContextExecutor = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(20))
    
    val f: Future[String] = Future[String] {
      Thread sleep 1000
      "hello scala"
    }
    
    // 完整写法,参数是一个函数:f: Try[T] => U
    f.onComplete((result: Try[String]) => result match {
      case Failure(exception) => println(exception)
      case Success(value) => println(value)
    })
    
    // 常用写法
    f onComplete {
      case Failure(exception) => println(exception)
      case Success(value) => println(value)
    }
    

    函数组合(Functional Composition)

    Future可以通过map、flatMap,filter和foreach等组合器,创建一个新的Future(可以有效避免Future中的多层嵌套)

    map

    val f1 = Future { List(1, 2, 3, 4, 5) }
    
    val f2 = f1.map(f1_v => {
      f1_v.appended(10).appended(11).appended(12)
    })
    
    f2 onComplete {
      case Success(value) => println(value)
      case Failure(exception) => println(exception)
    }
    

    flatMap

    FlatMap操作会把自身的值映射到其他future对象上,并随着该对象计算完成的返回值一起完成计算
    结合下面的For-comprehensions一起看

    val f1 = Future { List(1, 2, 3, 4, 5) }
    
    val f2 = f1.flatMap(f1_v => {
      Future {
        f1_v.appended(10).appended(11).appended(12)
      }
    })
    
    f2 onComplete {
      case Success(value) => println(value)
      case Failure(exception) => println(exception)
    }
    

    filter

    val f = Future { 5 }
    val g = f filter { _ % 2 == 1 }
    val h = f filter { _ % 2 == 0 }
    
    g onComplete {
      case Success(value) => println(value)
      case Failure(exception) => println(exception)
    }
    
    h onComplete {
      case Success(value) => println(value)
      case Failure(exception) => println(exception)
    }
    

    foreach 好像类似onSuccess???

    val f1 = Future { List(1, 2, 3, 4, 5) }
    
    f1.foreach(f1_v => {
      println(f1_v)
    })
    

    For-comprehensions 当异步f1的结果比异步f2的结果大的时候进行某些异步操作

    val f1 = Future { Random.nextInt(10000) }
    val f2 = Future { Random.nextInt(10) }
    
    // 第一种写法
    val f3 = for {
      f1_v <- f1
      f2_v <- f2
      if f1_v > f2_v
    } yield "成功"
    
    // 第二种写法
    val f3 = f1.flatMap(f1_v => {
      f2.withFilter(f2_v => f1_v > f2_v).map(_ => "成功")
    })
    
    f3 onComplete {
      case Success(value) => println(value)
      case Failure(exception) => println("ERR>>>", exception.getMessage)
    }
    

    recover

    val f1 = Future {
      Random.nextInt(10000)
    }
    
    // 使用recover,处理Future中的异常
    val f2 = f1.map((f1_v: Int) => {
      if (f1_v > 1000) {
        "success and do something..."
      } else {
        throw new Exception("user defined exception...")
      }
    }).recover(new PartialFunction[Throwable, String] {
      override def isDefinedAt(x: Throwable): Boolean = x.getMessage.contains("user defined")
    
      override def apply(v1: Throwable): String = v1.getMessage
    })
    
    // 如果没有recover,就会因为抛异常走到Failure分支
    f2 onComplete {
      case Success(value) => println(value)
      case Failure(exception) => println("ERR>>>", exception.getMessage)
    }
    
    // 简化写法
    val f3 = f1.map((f1_v: Int) => {
      if (f1_v > 1000) {
        "success and do something..."
      } else {
        throw new Exception("user defined exception...")
      }
    }).recover({
      case throwable: Throwable => throwable.getMessage
    })
    
    // 如果没有recover,就会因为抛异常走到Failure分支
    f3 onComplete {
      case Success(value) => println(value)
      case Failure(exception) => println("ERR>>>", exception.getMessage)
    }
    

    recoverWith

    val f1 = Future {
      throw new Exception("user defined exception...")
      Random.nextInt(10000)
    }
    
    val f2 = f1.recoverWith(new PartialFunction[Throwable, Future[String]] {
      override def isDefinedAt(x: Throwable): Boolean = x.getMessage.contains("user defined")
      override def apply(v1: Throwable): Future[String] = Future {
        v1.getMessage
      }
    })
    
    // 这里仍然会走success分支
    f2 onComplete {
      case Success(value) => println(value)
      case Failure(exception) => println("ERR>>>", exception.getMessage)
    }
    
    // 简化写法
    val f3 = f1.recoverWith({
      case throwable: Throwable => Future {
        throwable.getMessage
      }
    })
    
    // 这里仍然会走success分支
    f3 onComplete {
      case Success(value) => println(value)
      case Failure(exception) => println("ERR>>>", exception.getMessage)
    }
    

    andThen

    经andThen返回的新Future无论原Future成功或失败都会返回与原Future一模一样的结果。

    val f1 = Future {
      throw new Exception("user defined exception...")
      Random.nextInt(10000)
    }
    
    val f2 = f1.andThen(new PartialFunction[Try[Int], String] {
      override def isDefinedAt(x: Try[Int]): Boolean = x.isSuccess
    
      override def apply(v1: Try[Int]): String = {
        println("andThen run", "do something...")
        "do something..."
      }
    })
    
    // andThen正常执行,但这里会走Failure分支(返回原Future的结果)
    f2 onComplete {
      case Success(value) => println(value)
      case Failure(exception) => println("ERR>>>", exception.getMessage)
    }
    
    // 简化写法
    val f3 = f1.andThen({
      case i: Try[Int] => {
        println("andThen run", "do something...")
        "do something..."
      }
    })
    
    // andThen正常执行,但这里会走Failure分支(返回原Future的结果)
    f3 onComplete {
      case Success(value) => println(value)
      case Failure(exception) => println("ERR>>>", exception.getMessage)
    }
    

    投影(Projections)

    如果原future对象失败了,失败的投影(projection)会返回一个带有Throwable类型返回值的future对象。如果原Future成功了,失败的投影(projection)会抛出一个NoSuchElementException异常。
    这个看不懂有什么用-_-||

    // 会打印异常
    val f = Future {
      2 / 0
    }
    for (exc <- f.failed) println(exc)
    
    // 不会打印异常
    val f = Future {
      2 / 1
    }
    for (exc <- f.failed) println(exc)
    

    Promises(futures也可以使用promises来创建)

    W3C上没看到的

    // type相当于声明一个类型别名,下面把String类型用S代替,通常type用于声明某种复杂类型,或用于定义一个抽象类型。
    type S = String
    // Session => Validation[T]声明一个函数类型,参数是Session返回值是Validation[T]
    type Expression[T] = Session => Validation[T]
    
    // 自身类型(self type),格式:this: T =>
    // this也可替换为self或其它不是关键字的别名。
    // 作用:指定可以混入的类的超类。这个特质只能混入给定类型的子类中。(只有AA的子类可以混入A)
    // 注:特质extends一个类时,可以保证其混入的类都是该类的子类;而特质指定自身类型时,可以保证它只能混入该类的子类。
    trait A { 
      this: AA =>
    }
    
    // class中的自身类型让类抽象了-该类在实例化时必须满足AA;相当于构造一个复合类型(A with AA)。
    class A {
      this: AA =>
    }
    
    // 自身类型声明为复合类型:
    this: X with Y with Z => 
    
    // 自身类型声明为结构类型:
    this: { def close: Unit } => 
    
    // this 别名,可以用除关键字之外的所有字段,不一定要是self
    class A { 
      self =>  // this alisa
      val x = 2 
      def foo = self.x + this.x 
    }
    
    // sealed用来保证在使用match的时候需要把所有可能出现的情况都写出来,如果漏掉一个,就会编译出错
    sealed trait A {}
    class A1 extends A {}
    class A2 extends A {}
    class A3 extends A {}
    
    // a 没有任何修饰符,不是A的成员变量,只是一个构造方法的参数
    // b val修饰的变量,是A的成员变量,默认生成get方法
    // c var修饰的变量,是A的成员变量,默认生成get和set方法
    class A (a: Int, val b: Int, var c: Int) {}
    

    Scala中的"->"和"<-"以及"=>"

    转自

    ->

    // ->只会出现在k->v里面
    val map: Map[String, Any] = Map("name" -> "zhangsan", "age" -> 12, "from" -> "china")
    

    <-

    // <-只会出现在for循环里面
    val map: Map[String, Any] = Map("name" -> "zhangsan", "age" -> 12, "from" -> "china")
    for ((key, value) <- map) {
        println(key, value)
    }
    

    =>

    // 用法一:
    type t1 = Int => Int // t1 是一个函数类型(多用来在参数中表示需要传入一个函数,其类型需符合 t1)
    
    // 用法二:匿名函数
    val t2: t1 = (i: Int) => i * i // t2 是一个匿名函数(本身就是一个函数,可以执行的)
    
    // 用法三
    // 放在 case 后面,略
    
    // 用法四:By-Name Parameters(传名参数)
    // 传名参数在函数调用前表达式不会被求值,而是会被包裹成一个匿名函数作为函数参数传递下去
    def test_1(i: => Int): Int = { // 如果传入的值是一个普通的 Int ,则没有什么区别,如果传入的值是一个函数,则传入的函数不会立即执行,如下示例:
      println("run test_1")
      i * i
    }
    def test_2(i: Int): Int = {
      println("run test_2")
      i * i
    }
    test_1(test_2(3))
    
    > 执行顺序如下
    > run test_1
    > run test_2
    > run test_2
    
  • 相关阅读:
    Catalan数
    C# & LINQ 对象克隆
    Rotate Image
    反转链表
    QtCreator调试程序时GDB崩溃
    Regular Expression Matching
    Wildcard Matching
    DFA与NFA
    Set Matrix Zeroes
    PCA原理
  • 原文地址:https://www.cnblogs.com/CSunShine/p/11976474.html
Copyright © 2020-2023  润新知