还没写完,不定期更新。

前言

这本书主要是Scala基础知识的快速介绍和简单罗列。并不全面。

0x00:case class 工厂方法实现

  1. class Car(val str: String) {
  2. }
  3. object Car {
  4. def apply(str: String) = new Car(str)
  5. }

0x01:推导

  1. val v = Vector(0, 1, 2, 3, 4)
  2. val result = for {
  3. n <- v
  4. if n % 2 == 0
  5. } yield {
  6. val u = n + 10
  7. u * 2
  8. }

0x02:反射

0x03:枚举

  1. object Level extends Enumeration {
  2. type Level = Value
  3. val Low, High = Value
  4. }

0x04:类型

Scala里类型和类是俩东西
额外参考
https://blog.csdn.net/hellojoy/article/details/81020832

  1. scala> classOf[List[Int]] == classOf[List[String]]
  2. res16: Boolean = true
  3. scala> typeOf[List[Int]] == typeOf[List[String]]
  4. res17: Boolean = false

0x05:统一访问原则

  1. trait Base {
  2. def f: Int
  3. }
  4. class Derived extends Base {
  5. val f = 1
  6. }

0x06:单元测试

推荐使用ScalaTest。里面的Assert特别好用,数据对比十分清晰。和Node.js中的PowerAssert一样,是目前遇到的最好断言显示方式。

0x07:组合表达式

把表达式用花括号包起来,返回结果默认为最后的表达式。

0x08:标记特征和case对象

  1. sealed trait Color
  2. case object Red extends Color
  3. case object Green extends Color
  4. object Color {
  5. val values = Vector(Red, Green)
  6. }

0x09:衔接Java

遍历Java的Iterator

必须要转换成Scala的Iterator,要不无法使用for,只能用while

  1. import scala.collection.JavaConverters._
  2. val scalaIterator = javaIterator.iterator().asScala
  3. for (x <- scalaIterator) {
  4. println(x)
  5. }

0x0A:隐式转换

触发规则

作用域规则:以单一表示符存在作用域中、伴生对象、回去伴生对象中查找这个类是否可以隐式转换
显示操作先行规则:若类型检查无误不会触发隐式转换

运行时保存类型信息

  1. (implicit classTag : scala.reflect.ClassTag[T])

函数

如果函数没参数可以不写括号

  1. def three = 1 + 2

匿名函数

  1. (x: Int) => x + 1
  2. val addOne = (x: Int) => x + 1

部分应用

  1. def adder(m: Int, n: Int) = m + n
  2. val add2 = adder(2, _: Int)
  3. add2(3)
  4. res: Int = 5

科里化

  1. def multiply(m: Int)(n: Int): Int = m * n
  2. multiply(2)(3)
  3. val timesTwo = multiply(2) _
  4. times(3)

除了方法之外的代码全是构造函数

private

内部类可以访问private
外部类不能访问private
但是Java中都可以

  1. class Outer{
  2. class Inner{
  3. private def f(){println("f")}
  4. class InnerMost{
  5. f() // 正确
  6. }
  7. }
  8. (new Inner).f() //错误
  9. }

protected

只有子类能访问protected
Java中同一个包中的也可以访问protected

  1. package p{
  2. class Super{
  3. protected def f() {println("f")}
  4. }
  5. class Sub extends Super{
  6. f()
  7. }
  8. class Other{
  9. (new Super).f() //错误
  10. }
  11. }

作用域保护

  1. private[x]
  2. protected[x]

除x包或x类可见外,其他访问全是private

包对象

由于JVM的限制,包可以包含类、对象、特质,但不能包含函数和变量。包对象是用来解决这个问题的语法糖,可以把函数或变量绑定到包上。每个包都可以有个包对象,在父包中定义它,如下代码:

  1. package com.horstmann.impatient
  2. package object people {
  3. val defaultName="John Q. Public"
  4. }
  5. package people {
  6. class Person {
  7. var name=defaultName // 从包对象拿到的常置
  8. }
  9. …….
  10. }
  11. }

defaultName可以通过com.horstmann.impatient.people.defaultName直接访问。
底层原理:
包对象被编译成名为package.class的JVM类,位于相应的包下。上例中把包对象代码放到一下位置是等价的com/horstmann/impatient/people/package.scala
包和引用详解

特质(Traits)和抽象类(Abstract Class)

抽象类定义方法但是不实现

  1. abstract class Shape {
  2. def getArea(): Int
  3. }

特质属性和方法

  1. trait Car {
  2. val brand: String
  3. def run(): Unit
  4. }

使用特质还是抽象类?

  • 优先使用特质。一个类可以继承多个特质,但只能继承一个抽象类。
  • 如果需要构造函数参数,则使用抽象类。抽象类可以定义构造函数参数,特质不行。

apply方法

对象直接加()就会直接调用apply方法

  1. class Foo {}
  2. object FooMaker {
  3. def apply() = new Foo
  4. }
  5. val newFoo = FooMaker()
  1. class Bar {
  2. def apply() = 0
  3. }
  4. val bar = new Bar
  5. bar()

函数也是对象

但方法不是

基本数据额结构

数组和列表区别

  • 数组 Array 有序可变
  • 列表 List 有序不可变

元组 Tuple 容纳不同类型

获取元素,从1开始

  1. tuple._1

元组和模式匹配结合

  1. hostPort match {
  2. case ("localhost", port) =>
  3. case (host, 80) =>
  4. case (_, _) =>
  5. }

创建两元素元组语法糖

  1. 1 -> 2
  2. res0: (Int, Int) = (1, 2)

映射 Map

初始化Map传递key和value元组即可

  1. Map(1 -> "one")
  2. Map(1 -> "one", 2 -> "two")
  3. Map((1, "one"), (2, "two"))

map.get(key)会返回下面特质的子类Some[T]或None

  1. trait Option[T] {
  2. def isDefined: Boolean
  3. def get: T
  4. def getOrElse(t: T): T
  5. }

获取value的方式

  1. val res = map.get(key)
  2. val value = if (res.isDefined) {
  3. res.get
  4. } else {
  5. 0 //key没有匹配到
  6. }

第二种

  1. val value = res.getOrElse(key)

第三种模式匹配

  1. val value = res match {
  2. case Some(n) => n
  3. case None => 0 //没匹配到的返回值
  4. }

函数组合子

flatMap = map + flatten

模式匹配


a会让变量模式变成常量模式,下面输出“没有匹配”

  1. object Demo {
  2. val a = 2
  3. def main(args: Array[String]) = {
  4. println(testPatternMatching(1))
  5. }
  6. def testPatternMatching(e: Int) = e match {
  7. case `a` => "haha: " + a
  8. case _ => "没有匹配"
  9. }
  10. }
  1. foo match {
  2. case List(0, _*) =>
  3. case _ =>
  4. }

变量绑定

  1. foo match {
  2. case Bar("test", e @ 12) => e
  3. case _ =>
  4. }

12则赋值给e,e作为匹配对象

语法糖

  • 如果只传一个参数可以用花括号代替小括号。
  1. println("haha")
  2. println{ "haha" }
  • 传名函数
    () => 可以省略 ()

这样写出来的代码就更像语言原生的了

  1. def foo(bar: => Boolan) =
  2. bar()
  3. foo(5 > 3)
  4. foo {
  5. 5 > 3
  6. }

偏函数

  1. foo {
  2. case (x, y)
  3. }

https://zhuanlan.zhihu.com/p/33165576

文档

https://scala-lang.org/files/archive/api/2.11.12/#package
某些Scala类是直接用的Java类,Scala文档中没有(例如String)。要去Java文档中看,地址:https://docs.oracle.com/javase/8/docs/api/overview-summary.html

总结

这本书没有《Scala编程》写的深入,还是推荐《Scala编程》,当然两本都看收货更多。

参考

《Scala编程》
《Scala编程思想》
Twitter Scala School
Effctive Scala
Implicit 详解