programming in Scala 学习(二)

(9-21章)


1. java通过private可以使类内部方法私有化,对外不可见。Scala除了private方式,还可以使用本地函数(内嵌在函数中的函数)实现,本地函数仅在包含它的函数代码块中可见,外部无法访问。在作用域方面,本地函数可以访问包含它的外层函数的入参,不需要再传入参数。


2. 函数是Scala的头等函数(first-class function)或头等结构,不仅可以像java那样定义和调用函数,还可以把函数写成匿名的函数字面量(function literal),例如(x: Int) => x+1,并把它们作为值(value)传递,可以用于赋值方式定义函数,或作为函数调用参数传递入参,或者只给出类型作为函数声明定义的入参,等等场合。函数字面量被编译到类,在运行期实例化为函数值,函数字面量与函数值的区别在于,函数字面量存在与源代码,函数值存在于运行期,这个区别很像类(源代码)和对象(运行期)之间的关系。用函数字面量是通过赋值定义一个函数,与def 关键字声明定义一个函数,两者写法规则的不同点需要区分留意。


3. 函数值是对象,如果愿意,可以将其存入变量,存入后的变量也是函数,变量名即函数名,可以用通常的  括号()  或  括号(参数)  编写此函数调用。


4. 函数字面量可以包含多条语句,用花括号包住函数体,当函数值被调用时,所有的语句将被执行,函数返回值是最后一行表达式产生的值。


5. 函数字面量更简短的表达方式:1)去除参数类型;2)去除无用字符,如多余的括号;3)使用下划线当作一个参数的占位符,函数字面量中可以使用多个下划线代表多个参数的占位,前提是每个参数在函数字面量中出现且仅出现一次,第一个占位符代表第一个参数,第二个占位符代表第二个参数,依此类推,有时使用占位符编译器可能无法推断出缺失的参数类型,可以在占位符后面写上冒号和指定缺失的参数类型,用括号括起来,明确告诉编译器参数类型。


6. 部分应用函数(partially applied function)可以使用一个下划线替换整个参数列表,如println(_)或println _,后者函数名和下划线之间,一定要有一个空格,否则编译器会认为是在说明一个不同带符号的名字。


7. Scala的重复可变参数---在参数类型之后放一个星号,例如,def echo( args : String*) = for( arg <- args ) println(arg),args的类型实际是数组Array[String],如果已有一个Array[String]数组,比如val arr = Array("a", "b", "c"),传入echo函数作为参数,不能写成echo(arr),需要写成echo(arr: _*),表示arr的每个元素当作参数传入,而不是单一的一个arr数组参数。


8. 如果程序符合Scala尾递归情况,编译器将检测并把到尾递归替换成一个回到递归函数开头的跳转,尾递归不会为每次递归调用产生新的堆栈结构,追踪堆栈打印信息可以看到,尾递归只对递归函数做一次函数压栈,每次尾递归调用都会跳转到这一次压栈的一个栈内完成。Scala尾递归使用局限较大,还是可以用while替代。


9. 函数字面量定义形式,可以带有在函数作用域之外定义的自由变量,这样的函数字面量在运行期创建的函数值(对象)被称为闭包(closure)。闭包对捕获的自由变量修改值的改变在闭包之外也可见。如果闭包使用了某个函数的本地变量,每次函数调用时会创建一个新闭包,每个闭包会访问闭包创建时活跃的变量值。闭包的函数值(对象)被编译器创建在堆中,不是栈里。


10. 高阶函数(high-order function),可以调用传入的函数值(不是函数名)做参数,配合参数的占位符与Scala支持的函数闭包功能,组织和简化代码。


11. Scala的类方法,如果没有实现(没有等号或方法体),它就是抽象的,具有抽象成员的类本身必须被声明为抽象的,在class关键字之前加上abstract修饰符,说明类有抽象的未实现的成员,抽象类不能被实例化。


12. Scala里禁止在同一个类中使用同样的名称定义字段和方法,java允许,原因是java为定义准备了4个命名空间(字段、方法、类型和包),Scala只有2个命名空间:值(字段、方法、包、单利对象)和类型(类和特质名)。


13. Scala的类和构造器可以交织在一起,体现为类名后面可以加参数,相当于传给默认主构造器的函数参数。一个类有一个主构造器和任意数量的辅助构造器,而每个辅助构造器都必须以对先前定义的辅助构造器或主构造器的调用开始。这样做带来的后果是,辅助构造器永远都不可能直接调用超类的构造器。子类的辅助构造器最终都会调用主构造器,只有主构造器可以调用超类的构造器。


14. Scala特质的两种常用方式:拓宽瘦接口为胖接口;定义可堆叠的改变(stackable modification)。通过extends关键字混入特质,隐式继承特质的超类,或者extends显示指明待扩展的超类,用with混入特质。


15. 特质像是具有具体方法的java接口,但又有不同,特质定义不能有任何“类”参数,而且特质处理super调用是运行时动态绑定。特质定义如果extends了其他超类,特质中重写的方法调用了super,前面都需要写上abstract override关键字。


16. Scala把类定义中,该类和继承的超类以及特质,以线性化的次序放在一起,首先是该类,然后根据类声明定义,从右向左按次序线性化超类和特质,依次实现可堆叠的调用行为,比如按上述线性化顺序依次对super调用。(page 147)


17. 定义了 case class + 类名,表示Scala的样本类(case class),编译器会自动为样本类添加与类名一致的工厂方法、toString、hashCode、equals等方法,样本类方便在模式匹配match---case编码中使用构造器模式,进行深度匹配。(page 176)


18. Scala的类型参数可以用于编写泛型和特质。默认情况下,Scala的泛型类型是非协变的子类型化(即泛型没有继承关系,跟java一样),但可以通过+号,比如+T,告诉编译器该泛型是协变的,支持继承关系,或者-T实现继承关系的逆变。(page 254)


19. new + 特质名+{类结构体},这个表达式产生混入了特质并被结构体定义的匿名类实例。


20. 用implicit标记的变量、方法、对象定义等,是Scala的隐式操作,编译时编译器将考虑隐式转换。结合泛型使用时,<% 表示隐式参数的视界,与上界<意义不一样,上界表示"子类"关系,视界表示隐式参数的"可当作..."关系,不要求是子类。(page 298)





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章