目录
返回值类型可以不指定,建议指定
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
基本使用
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