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
原文地址:https://www.cnblogs.com/CSunShine/p/11976474.html