Programming in Scala的阅读笔记

两年前阅读《scala编程》(Programming in Scala)一书时做的一些零碎笔记。
注:当时PIS这本书还是第一版,里面是基于scala2.7的,有些类已经过时,比如RichString已被StringOps替代。

1) package名字可以与实际文件路径不同

2) class前面加public在eclipse会提示错误? 多此一举

3) 定义object 名字大写还是小写? scala源代码里有很多都是小写,但其他开源代码里都和class一样首字母大写
是否有特定说明?

4) class A private(str:String) 注意,这个构造函数中的变量没有声明为val或者var,
这种情况下,会生成private的setter和getter
如果 class A private(val str:String) 则会生成public的getter和setter,这是一个细节点
更新: 注意,var才有setter方法,方法名称为 xxx_$eq(xxx) ,val的只有getter,没有setter

5) i++或者++i 在scala中不起作用,必须用 i=i+1 或者 i+=1

6) scala把二元操作表达式 1 -> "A"转换为 (1).->("A"),任何对象都可以调->方法,并返回键值对的二元组(tuple)
任何对象都能调用->方法的机制为隐式转换。

7) RichString自2.7x之后已经被改为了scala.collection.immutable.StringOps 原先是scala.runtime包下
真坑爹,居然不能兼容。见:http://www.scala-lang.org/node/9901

8) p24,不能直接写 println 10 (此时小括号不可省), 但可以写成 Console println 10,需要注明方法的所有者。

9) p27,List不支持append操作,变通的方式是newEle::myList然后再reverse myList

10) p28, 元组(tuple)的索引是由1开始,而非0开始。

11) Arry,List,Set等,在创建一个集合时范型类型 [Type] 都可省,

  val arr = Array("A","B");  
  val list = List(1,2,3)

12) 可变和不可变集合的 += 操作含义不同
不可变 imSet += newEle 等价于 imSet = imSet + newEle
可变 mSet += newEle 等价于 mSet.+=(newEle) 是方法而非操作符

13) p288 import可以很细粒度,只导入某个方法, import A.method

14) p266 抽象成员不许要加abstract,只要不赋值便是抽象的,但注意val与var的区别(var除了getter还有setter)

    hongjiang@whj /tmp/dd % cat A.scala
    abstract class A { var a:Int }

    hongjiang@whj /tmp/dd % javap A
    Compiled from "A.scala"
    public abstract class A extends java.lang.Object 
                        implements scala.ScalaObject{
        public abstract int a();
        public abstract void a_$eq(int);  // var成员有赋值的setter方法
        public A();
    }

而 val则没有 setter方法。
抽象var,实际上也是抽象了getter/setter,并没有一个真正的var成员。

15) p418 给 this起别名

  class A {self =>   // 对A.this的别名,这里可以随意用什么变量名,比如outer, a都可以
    class B {
      // self is the enclosing A, synonymous for A.this
    }
  }

16) p269 1) 预初始化字段,-> 不仅限于匿名类。2) lazy修饰。 TODO 这个地方需要展开。

17) p274 抽象类型,type SuitableFood <: Food 定义所有Food的子类。 <: 表示上界

18) p254 协变与逆变。 trait Queue[ +T ] {} 表示为协变
比如 S继承于T,则 Queue[S] 也继承于 Queue[T]
而逆变用 Queue[-T]表示,与上面正相反, Queue[T] 将继承于 Queue[S]

19) p256 与java不同,scala中的数组不是协变的。
需要与java遗留方法交互时,可以将T类型数组造型为任意T的超类型数组

 val a1 = Array("abc");  
 val a2:Array[Object] = a1.asInstanceOf[Array[Object]]

20) 混入Ordered特质(trait),则可以对对象用 <,>,<=,>=来做比较。

21) 元组中的类型不一致,不可迭代。

22) scala中的方法参数都是val,不可被重新赋值(不可变).

23) p135 scala中的相等操作“==”被设计为对类型表达透明,即对值类型和引用类型不像java区分
对引用类型==被视为继承自Object的equals方法的别名。
若有需要用java中的==场景,则使用 AnyRef.eq 方法。x eq y 是java中的 x==y
==方法在Any中被定义为final的。

24) p379 存在类型,java中的Iterator<?>在scala中可写为:Iterator[T] forSome {type T}
java中的Iterator<? extends Component> 可写为:

    Iterator[T] forSome {type T <: Component}

表达形式为: type forSome{ declarations}

它可以缩写,比如:

  Iterator[T] forSome {type T}

可简写为: Iterator[_]

  Iterator[T] forSome {type T <: Component }

可简写为: Iterator[ _ <: Component ]

25) p375 注释
@SerialVersionUID(1234L)
@serializable
@throws(classOf[IOException])

26) p217 若需要对一个List不断加元素,可考虑用ListBuffer
listBuffer += newEle // 加在后边。
3 +: myListBuf // 元素加在前边。

27) scala2.9之后 Application@deprecated,用App替代

28) scala2.8 @tailrec 该注释用来检查方法是否可用tail recursion来优化

29) 当函数使用return 返回对象时,必须声明函数的返回类型,不能省略

Programming in Scala的阅读笔记》上有2个想法

  1. 谢谢你的总结 但第21点 tuple是可以迭代的 因为case class 和 tuple 都是extends Product. 而 product 有 productIterator方法会返回一个Iterator[Any].

发表评论

电子邮件地址不会被公开。 必填项已用*标注