这本书我是2013年买的,当时看了一部分,然后又忘了,现在重新阅读。
Scala将OOP和函数式编程有机结合,动静兼备。前面的基本招式通读后,基本上可以理解。但是后面的类型系统,协变型变,定界延续目前还搞不懂,暂时略过。
Scala解释器的使用。
val,var声明值和变量。
有7中数值类型:Byte,Char,Short,Int,Long,Float,Double,Boolean,和Java不同的是这些都是类。
Scala中使用方法进行数值类型的转换,而不是强制类型转换。
和Java,C++
不同的是,Scala中没有++,--操作符,要使用+=1。
()
操作符背后的实现原理是apply
方法。
if表达式有值。
{}块也有值,值是最后一个表达式的值。这个特性对于要分多步来初始化val的情况很有用。
Unit等同于Java,C++中的void。
赋值语句本身没有值,是Unit。
定义函数的时候,最好不使用return。
Scala中没有Checked Exception。
定长数组是Array, 变长数组是ArrayBuffer。
用 for(e <- arr)
遍历元素。
用 for(e <- arr if ...) yield ...
转换数组。
Scala数组和Java数组互操作。
Scala中没有可变的树形映射,可以选择Java的TreeMap。
元组可以用于函数需要返回不止一个值的情况。
Scala为每个字段生成getter,setter
方法,不过可以通过private,val,var,private[this]
控制这个过程。
如果需要JavaBeans版的getter,setter
方法,可以使用BeanProperty注解。
Scala中类有一个主构造器(primary constructor),任意多个辅助构造器(auxiliary constructor),名称是this。每个辅助构造器都必须开始于调用其他辅助构造器或者主构造器。
练习5.注意BeanProperty包路径变了,scala.beans.BeanProperty
。
➜ ch05 git:(master) scalac Student.scala
➜ ch05 git:(master) javap -private Student
Compiled from "Student.scala"
public class Student {
private java.lang.String name;
private long id;
public java.lang.String name();
public void name_$eq(java.lang.String);
public void setName(java.lang.String);
public long id();
public void id_$eq(long);
public void setId(long);
public java.lang.String getName();
public long getId();
public Student(java.lang.String, long);
}
在Java中会使用单例对象的地方,Scala中用对象,单例模式。
搞清类和伴生对象(companion object)的关系。
定义枚举的方法。
包对象(package object)。
可以在任何地方声明包引入。
要知道Scala的继承层级。
能看懂,但是自己怕是写不出来,需要练习。
用完Source对象,要记得close。
如果要查看某个字符,但是不处理掉它,使用source.buffered方法(类似C++中的istream::peek
,或java中的PushbackInputStream
)。
Scala没有提供读取二进制文件的方法,要使用java类库。写文件也要使用java库java.io.PrintWriter
。
可以编写shell脚本。
Scala和Java不能多重继承(菱形继承问题)。
特质可以同时拥有抽象方法和具体方法,类可以实现多个特质。
实现特质用的extends,而不是implements,实现多个特质用with(奇怪么? extends A with B
,A with B
先是一个整体,然后由类扩展)。所有Java接口都可作为Scala的trait使用。
注意引入特质后,类的构造器执行顺序。
特质不能有构造器参数。
自身类型(self type)可以解决特质间的循环依赖。
操作符的优先级。
apply, update可以简化方法的调用。
unapply,unapplySeq和模式匹配的关系。
函数是一等公民。
所有集合都扩展自Iterable trait。
Java中ArrayList和LinkedList实现了共同的List接口,使得编写要考虑随机访问效率的代码比较困难,后来加入的RandomAccess(1.4)就是应对这个的。
Scala优先采用不可变集合。
Scala中模式匹配match无需在每个分支后面break。
支持守卫,而无需把每种情况的case都列出来。
倾向于使用类型模式匹配,而不是isInstanceOf操作符。匹配发生在运行时,所以泛型会擦除。
模式匹配用于数组,列表,元组背后是提取器机制,对应的伴生对象实现unapply,unapplySeq方法。比如Array的:
/** Called in a pattern match like `{ case Array(x,y,z) => println('3 elements')}`.
*
* @param x the selector value
* @return sequence wrapped in a [[scala.Some]], if `x` is a Seq, otherwise `None`
*/
def unapplySeq[T](x: Array[T]): Option[IndexedSeq[T]] =
if (x == null) None else Some(x.toIndexedSeq)
// !!! the null check should to be necessary, but without it 2241 fails. Seems to be a bug
// in pattern matcher. @PP: I noted in #4364 I think the behavior is correct.
样例类(Case Class
)的使用场景和作用。List就是用样例类实现的。
推荐使用Option表示可有可无的东西。
Annotation,StaticAnnotation, ClassfileAnnotation。
类型变量界定,上界<:
,下界>:
。
视图界定<%
,表示可以隐式转换的情况。
要实例化一个Array[T]
,需要一个Manifest[T]
对象,这么复杂?因为JVM中泛型擦除。
读于 2018.12.29 杭州