Scala By Example: 泛型

本文探讨了Scala中泛型二叉搜索树的实现方法,包括如何定义泛型集合并确保元素间的比较性,以及如何利用协变和逆变优化栈类的设计。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

泛型二叉搜索树

通过参数化型别,我们可以将先前的 IntSet 以泛型风格重写

   1: // from IntSet to Set
   2: abstract class Set[A] {
   3:     def incl(x: A): Set[A]
   4:     def contains(x: A): Boolean
   5: }
   6: // ... But

非常直接了当的做法。类似的代码在 Groovy 中将能够顺利编译并(多数情况下)正确运行,但是在 Scala 中,我们将遇到小小的问题:在 IntSet 中,我们在 incl 和 contains 方法中均调用了 Int 的 > 和 < 方法,但当使用泛型的时候,我们无法保证 A 具有这两个方法。为此,我们必须对 A 进行小小的修饰:要求 A 必须已混入了 trait Ordered

   1: // The parameter declaration A <: Ordered[A] introduces A as a type
   2: // parameter which must be a subtype of Ordered[A], i.e. its values must be
   3: // comparable to values of the same type.
   4: trait Set[A <: Ordered[A]] {
   5:     def incl(x: A): Set[A]
   6:     def contains(x: A): Boolean
   7: }
   8:  
   9: class EmptySet[A <: Ordered[A]] extends Set[A] {
  10:     def contains(x: A) = false
  11:     def incl(x: A): Set[A] =
  12:         new NonEmptySet(x, new EmptySet[A], new EmptySet[A])
  13: }
  14:  
  15: class NonEmptySet[A <: Ordered[A]](elem: A, left: Set[A], right: Set[A])
  16:     extends Set[A] {
  17:     def contains(x: A): Boolean =
  18:         if(x < elem) left contains x
  19:         else if(x > elem) right contains x
  20:         else true
  21:     def incl(x: A): Set[A] =
  22:         if(x < elem) new NonEmptySet(elem, left incl x, right)
  23:         else if(x > elem) new NonEmptySet(elem, left, right incl x)
  24:         else this
  25: }
  26:  
  27: case class Num(value: Double) extends Ordered[Num] {
  28:   def compare(that: Num): Int =
  29:     if(this.value < that.value) -1
  30:     else if(this.value > that.value) 1
  31:     else 0
  32: }
  33:  
  34: val s = new EmptySet[Num].incl(Num(1.0)).incl(Num(2.0))
  35: println(s.contains(Num(1.5)))
  36: // Int does not conform to type parameter bound Ordered[Int]
  37: // val w = new EmptySet[Int] // Error!
问题是,如果你在设计 Num 类的时候没有考虑到 Set 的应用,那么你将不会将 Num 声明为 Ordered 的子类,从而无法在日后的场合应用以上的代码,同样的道理,你无法对 EmptySet 应用 Int、Double 或其它显而易见可能会被用到的类。原书中提供了另一中解决方案(view bounds),可惜我无法找到运行它的方法,鉴于 view bounds 将在第 15 节详细介绍,这里就先略过了。#TBD
协变 & 逆变
在铅笔书里有那么 1% 的篇幅提到了协变和逆变,并且总结得非常好:本节会让你觉得有点头痛。
默认的情况下,Scala 两者都不支持,通过修饰符 +/- 可以分别实现协/逆变。如同原书所说,其逻辑相当的 conservative。考虑如下代码
   1: class Stack[+A] {
   2:   def push[B >: A](x: B): Stack[B] = new NonEmptyStack(x, this)
   3: }

通过指定 A 是 B 的子类强迫 push 接收 A 或其基类型。不仅如此,其返回值也会根据 B 的类型自动做相应的改变!(说实话,除了这个自动改变返回值类型的特点外,我一点也无法领会 Scala 在类型处理上的美妙之处,作为强测试的拥护者,我真的真的不在意强类型,but,目前我还没有学完,不是吗?)

Nothing

作为递归的起点,空的 Stack 可以写作 class EmptyStack extends Stack[A],但是引入协变后,从逻辑上,我们只需要一个对象就可以表示空栈
   1: abstract class Stack[+A] {
   2:     def push[B >: A](x: B): Stack[B] = new NonEmptyStack(x, this)
   3:     def isEmpty: Boolean
   4:     def top: A
   5:     def pop: Stack[A]
   6: }
   7:  
   8: object EmptyStack extends Stack[Nothing] {
   9:     def isEmpty = true
  10:     def top = error("EmptyStack.top")
  11:     def pop = error("EmptyStack.pop")
  12: }
  13:  
  14: class NonEmptyStack[+A](elem: A, rest: Stack[A]) extends Stack[A] {
  15:     def isEmpty = false
  16:     def top = elem
  17:     def pop = rest
  18: }
一个对象就可以了。在此,Nothing 是所有类的子类;对应的 Any则是所有类的超类。(突然想吼指环王的台词:One ring to rule them all...)
Tuple
刚开始接触元组(没有雪月饼)的时候,我以为这是 Scala 的核心语法,但实际上,所有的功能都由 Tuple 类来提供。它们是如此的方便以至于 Scala 最终为其提供了特殊的语法 (...)。最后提醒下,Tuple 属于 Case 类。
函数
Technorati 标签: Scala
不单单元组,函数也是由类来实现的。例如一个二元函数可以视作 trait Function1[-A, +B] { def apply(x: A): B } 的一个实例(看到这些都被解构开来感觉很奇怪)。在这里可以同时看到逆变和协变的应用。
PS. Scala 处理类型转换的方式让人耳目一新,也让人头痛无比。简单的说,我真的不喜欢强类型。
PS II. 但不喜欢归不喜欢,我决定试一试。记得在刚刚开始用 Groovy 时,闭包也让我如堕五里云雾,但用了一年以后,闭包就变成本能了……But,闭包倒是一开始就喜欢。
1 Introduction 1 2 A First Example 3 3 Programming with Actors and Messages 7 4 Expressions and Simple Functions 11 4.1 Expressions And Simple Functions . . . . . . . . . . . . . . . . . . . . . . 11 4.2 Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 4.3 Conditional Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 4.4 Example: Square Roots by Newton’s Method . . . . . . . . . . . . . . . . 15 4.5 Nested Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 4.6 Tail Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 5 First-Class Functions 21 5.1 Anonymous Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 5.2 Currying . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 5.3 Example: Finding Fixed Points of Functions . . . . . . . . . . . . . . . . 25 5.4 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 5.5 Language Elements Seen So Far . . . . . . . . . . . . . . . . . . . . . . . 28 6 Classes and Objects 31 7 Case Classes and Pattern Matching 43 7.1 Case Classes and Case Objects . . . . . . . . . . . . . . . . . . . . . . . . 46 7.2 Pattern Matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 8 Generic Types and Methods 51 8.1 Type Parameter Bounds . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 8.2 Variance Annotations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56iv CONTENTS 8.3 Lower Bounds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 8.4 Least Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 8.5 Tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 8.6 Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 9 Lists 63 9.1 Using Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 9.2 Definition of class List I: First Order Methods . . . . . . . . . . . . . . . 65 9.3 Example: Merge sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 9.4 Definition of class List II: Higher-Order Methods . . . . . . . . . . . . . 70 9.5 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 10 For-Comprehensions 79 10.1 The N-Queens Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 10.2 Querying with For-Comprehensions . . . . . . . . . . . . . . . . . . . . . 81 10.3 Translation of For-Comprehensions . . . . . . . . . . . . . . . . . . . . . 82 10.4 For-Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 10.5 Generalizing For . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 11 Mutable State 87 11.1 Stateful Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 11.2 Imperative Control Structures . . . . . . . . . . . . . . . . . . . . . . . . . 91 11.3 Extended Example: Discrete Event Simulation . . . . . . . . . . . . . . . 92 11.4 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 12 Computing with Streams 99 13 Iterators 103 13.1 Iterator Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 13.2 Constructing Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 13.3 Using Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值