主要来自 Scala 语言发明人 Martin Odersky 教授的 Coursera 课程 《Functional Programming Principles in Scala》



3. Data and Abstraction

3.1 Class Hierarchies

这一集字幕不同步​​-,-​​,听得有点费力!

类的概念和其他语言里面很相似,基类,子类,父类啥的叫法差不多。在 Scala 中,所有用户自定义的类都是另外一个类的子类,如果没有显式给定父类,java 里面默认继承 java.lang,scala 里面是 Object。无论基类中的方法有没有具体实现,子类都可以用 ​​override​​​ 重新定义,回想起之前强大的 ​​toString​​ 了吗?

举一个二叉树的例子:

package week3  object insets {   val t1 = new NonEmpty(3, Empty, Empty)          //> t1  : week3.NonEmpty = {.3.}   val t2 = t1 incl 4                              //> t2  : week3.IntSet = {.3{.4.}}   val t3 = new NonEmpty(5, Empty, Empty)          //> t3  : week3.NonEmpty = {.5.}   t2 union t3                                     //> res0: week3.IntSet = {{{.3.}4.}5.} }  abstract class IntSet {  // 抽象类作为基类,无法实例化,定义了三个接口   def contains(x: Int): Boolean // 查找是否包含 x   def incl(x: Int): IntSet // 如果 x 不存在,将 x 放入二叉树中   def union(x: IntSet): IntSet  // 两棵树融合   }  object Empty extends IntSet { // Empty 是 IntSet 的 subclass,`object` 表示单例模式,所有空节点都可以用一个对象来表示   def contains(x: Int): Boolean = false   def incl(x: Int): IntSet = new NonEmpty(x, Empty, Empty)   def union(other: IntSet): IntSet = other   override def toString = "." // 空节点打印"." }  class NonEmpty(elem: Int, left: IntSet, right: IntSet) extends IntSet {   def contains(x: Int): Boolean =     if (x < elem) left contains x     else if (x > elem) right contains x     else true    def incl(x: Int): IntSet =     // 实际上创建了一个新树,新树和旧树共用未改变的子树     // 这个叫 persistent data structure,是把函数式编程扩展到 collections 的关键之一     // 反正他是这么说的 `-,-`     if (x < elem) new NonEmpty(elem, left incl x, right) // 一重一重地复制节点     else if (x > elem) new NonEmpty(elem, left, right incl x)     else this    def union(other: IntSet): IntSet =     ((left union right) union other) incl elem  //     override def toString = "{" + left + elem + right + "}" //强大的递归啊 } 

3.2 How Classes Are Organized

没学过 java,估计和 java 中 package 管理一样。

在源码最顶端写上 ​​package week3​​​ 表示这个文件的 object 或者 class 属于这个包。要使用某一个类,可以在源码中用全名 ​​week3.classA​​,也可以像 python 一样在最开始 import,源码中间用类名:


  • import week3.classA:导入类 classA
  • import week3.{classA, classB}:导入两个类
  • import week3._ :导入包所有(通配符导入方法)

除了从包导入,还可以从 object 导入。所有 Scala 程序默认导入一些 entities,比如 scala 中的 Int,java.lang 中的 Object,scala.Predef 中的断言等。更多信息可以查看 scala 的​​标准库​​。

在 java 和 scala 中,一个类只能有一个父类(单继承),如何实现多继承,scala 中采用 traits。trait 像 java 里面的接口,偏抽象,但是更强大,可以包含 field 和具体方法,但是不能有value参数。子类可只能继承一个父类,但是可以继承任意多个 traits,例如:​​class Square extends Shape with Planar with Moveble​​。

scala 类型结构如下,实线表示继承,虚线表示隐式转化。


  • ​Any​​是所有类型的基本类,包含的方法有:‘==’,‘!=’,‘equals’,‘hashCode’,‘toString’
  • ​AnyVal​​是数值类型的基本类。
  • ​AnyRef​​是所有引用类型的基本类,也是 java.lang.Object 的别名。
  • ​Nothing​​是所有类的子类型。主要作用是异常类与collection中的一个空元素。
  • ​Null​​ 是所有类的子类型。但是与 AnyVal 的子类型不兼容。

Scala 中的函数式编程基础(三)_子类

Q:​if (true) 1 else False​​ 的返回类型是什么?

A:int 和 boolean 类型,返回父类 AnyVal。

3.3 Polymorphism

Polymorphism 意味着函数可以以多种类型出现。一张 PPT 总结 Polymorphism:

Scala 中的函数式编程基础(三)_子类_02

假设我们要建立一个 list 类,它可能包含了不同的数据类型(整数,布尔,list自身类型等),例子如下:

Scala 中的函数式编程基础(三)_基础_03

这时需要用泛型来表示。新建一个package叫week4,在其中新建一个 trait。它的两个‘子类’分别为 Cons 和 Nil,分别表示含有元素的节点和空节点。

package week4  // [T] 是类型参数,比如int,double之类。是泛型编程的基础 trait List[T] {   def isEmpty: Boolean   def head: T   def tail: List[T] }  class Cons[T](val head: T, val tail: List[T]) extends List[T] {   def isEmpty = false   // head 和 tail 已经在初始化中实现 }  class Nil[T] extends List[T] {   def isEmpty = true   def head: Nothing = throw new NoSuchElementException("Nil.head")   // Nothing 是任何类型的子类,所以也是 T 的子类   def tail: Nothing = throw new NoSuchElementException("Nil.tail") } 

在 week4 中新建一个 scala worksheet,测试一下上述代码:

package week4  import week4._  object nth {   // 创建一个含有一个元素的 list   def singleton[T](elem: T) = new Cons(elem, new Nil)         //> singleton: [T](elem: T)week4.Cons[T]   singleton[Int](3)         //> res0: week4.Cons[Int] = week4.Cons@71be98f5   singleton(3) // 编译器可以从 3 推到出 T 是 Int     // 寻找 list 中的第 n 个元素   def nth[T](n: Int, xs: List[T]): T =     if (xs.isEmpty) throw new IndexOutOfBoundsException     else if (n == 0) xs.head     else nth(n - 1, xs.tail)        //> nth: [T](n: Int, xs: week4.List[T])T    // 创建一个 list  = [1, 2, 3]   val list = new Cons(1, new Cons(2, new Cons(3, new Nil)))   nth(2, list)         //> res2: Int = 3 } 

小记


这里是课程前四次的大概内容,因为第一次课是教你怎么安装,所以实际内容只有三次课,后面还有四次课。总体来说,函数式编程给人很多启发,但是如果不是真正需要用,也不宜占用太多时间去学习。暑假要去实习了,等下学期再学吧。





by:daniel-D

from:http://www.cnblogs.com/daniel-D/



主要来自 Scala 语言发明人 Martin Odersky 教授的 Coursera 课程 《Functional Programming Principles in Scala》



3. Data and Abstraction

3.1 Class Hierarchies

这一集字幕不同步​​-,-​​,听得有点费力!

类的概念和其他语言里面很相似,基类,子类,父类啥的叫法差不多。在 Scala 中,所有用户自定义的类都是另外一个类的子类,如果没有显式给定父类,java 里面默认继承 java.lang,scala 里面是 Object。无论基类中的方法有没有具体实现,子类都可以用 ​​override​​​ 重新定义,回想起之前强大的 ​​toString​​ 了吗?

举一个二叉树的例子:

package week3  object insets {   val t1 = new NonEmpty(3, Empty, Empty)          //> t1  : week3.NonEmpty = {.3.}   val t2 = t1 incl 4                              //> t2  : week3.IntSet = {.3{.4.}}   val t3 = new NonEmpty(5, Empty, Empty)          //> t3  : week3.NonEmpty = {.5.}   t2 union t3                                     //> res0: week3.IntSet = {{{.3.}4.}5.} }  abstract class IntSet {  // 抽象类作为基类,无法实例化,定义了三个接口   def contains(x: Int): Boolean // 查找是否包含 x   def incl(x: Int): IntSet // 如果 x 不存在,将 x 放入二叉树中   def union(x: IntSet): IntSet  // 两棵树融合   }  object Empty extends IntSet { // Empty 是 IntSet 的 subclass,`object` 表示单例模式,所有空节点都可以用一个对象来表示   def contains(x: Int): Boolean = false   def incl(x: Int): IntSet = new NonEmpty(x, Empty, Empty)   def union(other: IntSet): IntSet = other   override def toString = "." // 空节点打印"." }  class NonEmpty(elem: Int, left: IntSet, right: IntSet) extends IntSet {   def contains(x: Int): Boolean =     if (x < elem) left contains x     else if (x > elem) right contains x     else true    def incl(x: Int): IntSet =     // 实际上创建了一个新树,新树和旧树共用未改变的子树     // 这个叫 persistent data structure,是把函数式编程扩展到 collections 的关键之一     // 反正他是这么说的 `-,-`     if (x < elem) new NonEmpty(elem, left incl x, right) // 一重一重地复制节点     else if (x > elem) new NonEmpty(elem, left, right incl x)     else this    def union(other: IntSet): IntSet =     ((left union right) union other) incl elem  //     override def toString = "{" + left + elem + right + "}" //强大的递归啊 } 

3.2 How Classes Are Organized

没学过 java,估计和 java 中 package 管理一样。

在源码最顶端写上 ​​package week3​​​ 表示这个文件的 object 或者 class 属于这个包。要使用某一个类,可以在源码中用全名 ​​week3.classA​​,也可以像 python 一样在最开始 import,源码中间用类名:


  • import week3.classA:导入类 classA
  • import week3.{classA, classB}:导入两个类
  • import week3._ :导入包所有(通配符导入方法)

除了从包导入,还可以从 object 导入。所有 Scala 程序默认导入一些 entities,比如 scala 中的 Int,java.lang 中的 Object,scala.Predef 中的断言等。更多信息可以查看 scala 的​​标准库​​。

在 java 和 scala 中,一个类只能有一个父类(单继承),如何实现多继承,scala 中采用 traits。trait 像 java 里面的接口,偏抽象,但是更强大,可以包含 field 和具体方法,但是不能有value参数。子类可只能继承一个父类,但是可以继承任意多个 traits,例如:​​class Square extends Shape with Planar with Moveble​​。

scala 类型结构如下,实线表示继承,虚线表示隐式转化。


  • ​Any​​是所有类型的基本类,包含的方法有:‘==’,‘!=’,‘equals’,‘hashCode’,‘toString’
  • ​AnyVal​​是数值类型的基本类。
  • ​AnyRef​​是所有引用类型的基本类,也是 java.lang.Object 的别名。
  • ​Nothing​​是所有类的子类型。主要作用是异常类与collection中的一个空元素。
  • ​Null​​ 是所有类的子类型。但是与 AnyVal 的子类型不兼容。

Scala 中的函数式编程基础(三)_子类

Q:​if (true) 1 else False​​ 的返回类型是什么?

A:int 和 boolean 类型,返回父类 AnyVal。

3.3 Polymorphism

Polymorphism 意味着函数可以以多种类型出现。一张 PPT 总结 Polymorphism:

Scala 中的函数式编程基础(三)_子类_02

假设我们要建立一个 list 类,它可能包含了不同的数据类型(整数,布尔,list自身类型等),例子如下:

Scala 中的函数式编程基础(三)_基础_03

这时需要用泛型来表示。新建一个package叫week4,在其中新建一个 trait。它的两个‘子类’分别为 Cons 和 Nil,分别表示含有元素的节点和空节点。

package week4  // [T] 是类型参数,比如int,double之类。是泛型编程的基础 trait List[T] {   def isEmpty: Boolean   def head: T   def tail: List[T] }  class Cons[T](val head: T, val tail: List[T]) extends List[T] {   def isEmpty = false   // head 和 tail 已经在初始化中实现 }  class Nil[T] extends List[T] {   def isEmpty = true   def head: Nothing = throw new NoSuchElementException("Nil.head")   // Nothing 是任何类型的子类,所以也是 T 的子类   def tail: Nothing = throw new NoSuchElementException("Nil.tail") } 

在 week4 中新建一个 scala worksheet,测试一下上述代码:

package week4  import week4._  object nth {   // 创建一个含有一个元素的 list   def singleton[T](elem: T) = new Cons(elem, new Nil)         //> singleton: [T](elem: T)week4.Cons[T]   singleton[Int](3)         //> res0: week4.Cons[Int] = week4.Cons@71be98f5   singleton(3) // 编译器可以从 3 推到出 T 是 Int     // 寻找 list 中的第 n 个元素   def nth[T](n: Int, xs: List[T]): T =     if (xs.isEmpty) throw new IndexOutOfBoundsException     else if (n == 0) xs.head     else nth(n - 1, xs.tail)        //> nth: [T](n: Int, xs: week4.List[T])T    // 创建一个 list  = [1, 2, 3]   val list = new Cons(1, new Cons(2, new Cons(3, new Nil)))   nth(2, list)         //> res2: Int = 3 } 

小记


这里是课程前四次的大概内容,因为第一次课是教你怎么安装,所以实际内容只有三次课,后面还有四次课。总体来说,函数式编程给人很多启发,但是如果不是真正需要用,也不宜占用太多时间去学习。暑假要去实习了,等下学期再学吧。