如何实现Scala的above,beside和toString

开发 后端
本文节选自Martin Odersky,Lex Spoon和Bill Venners所著,Regular翻译的《Programming in Scala》的第十章。Scala是一种针对 JVM 将函数和面向对象技术组合在一起的编程语言。

接下来一步,我们将在类Element中实现方法above。把一个元素放在另一个上面是指串连这两个元素的contents值。因此方法above的***个草案看上去可能是这样的:

  1. def above(that: Element): Element =  
  2.  new ArrayElement(this.contents ++ that.contents)  
++操作符串连两个数组。Scala里的数组被表示为Java数组,但是支持更多的方法。特别是,Scala里的数组继承自类scala.Seq,能够表现象序列这样的结构并包含许多访问和转换序列的方法。本章会解释某些数组方法,更全面的讨论将在第17章。

51CTO编辑推荐:Scala编程语言专题

实际上,前面展示的代码并不完全足够,因为它不允许你把不同长度的元素堆叠在一起。然而本节为了让事情保持简单,我们会任由其状态并仅仅把相同长度的元素传递给above。10.14节里,我们会给above做个改良,这样客户就能用它组合不同长度的元素了。

下一个要实现的方法是beside。把两个元素靠在一起,我们将创造一个新的元素,其中的每一行都来自于两个元素的相应行的串连。如前所述,为了保持事情简单我们会一开始假设两个元素高度相同。这产生了方法beside的下列设计:

  1. def beside(that: Element): Element = {  
  2.  val contents = new Array[String](this.contents.length)  
  3.  for (i < - 0 until this.contents.length)  
  4.   contents(i) = this.contents(i) + that.contents(i)  
  5.  new ArrayElement(contents)  
  6. }  
beside方法首先分配了一个新数组,contents,并串连this.contents和that.contents中相应的数组元素来填充。最终产生了新的ArrayElement包含了新的contents。

尽管beside的这个实现可以工作,但它是指令式风格,马脚露在我们索引数组的循环。这个方法可以替代缩减成一个表达式:

  1. new ArrayElement(  
  2.  for (  
  3.   (line1, line2) < - this.contents zip that.contents  
  4. ) yield line1 + line2  
  5. )  
这里,this.contents和that.contents两个数组被使用zip操作符转换为一个对子的数组(可以称为Tupele2)。zip方法从它的两个参数中拣出相应的元素并组织成对子数组。

例如,表达式:

  1. Array(123) zip Array("a""b")  
将生成:
  1. Array((1"a"), (2"b"))  
如果两个操作数组的其中一个比另一个长,zip将舍弃余下的元素。在上面的表达式中,左操作数的第三个元素,3,没有组成结果的部分,因为它在右操作数中没有相对的元素。

结果数组然后通过for表达式被枚举遍历。这里,表达式“for ((line1, line2) < - ...”允许你在一个模式:pattern中命名对子的两个元素,也就是说,line1现在代表对子的***个元素,line2代表第二个。Scala的模式匹配系统将在第15章描述。现在,你可以就把这当作在每次枚举中定义两个val,line1和line2的方式。

for表达式有个yield部分能产生结果。结果与枚举遍历的表达式类型一致,也就是说,是数组。数组的每个元素都是相应行,line1和line2串连的结果。因此这段代码的最终结果与前一个版本的beside一样,不过因为它避免了显示的数组索引,结果用一种更少犯错的方式实现了。

你还需要一个显示元素的方式。通常,可以通过定义toString方法返回元素格式化成的字串做到。下面是它的定义:

  1. override def toString = contents mkString "\n" 
toString的实现使用了mkString,它被定义在所有序列中,包括数组。正如你在7.8节中看到的,像“arr mkString sep”这样的表达式能返回数组arr所有元素组成的字串。通过调用toString方法每个元素被映射为字串。分隔符字串seq被插入到连续的元素字串当中。因此表达式“contents mkstring "\n"”格式化contents数组为字串,其中每个数组元素占据一行。

请注意toString没有带空参数列表。这个遵循了统一访问原则的建议,因为toString是一个纯的不带任何参数的方法。

附加了这三个方法,类Element现在看上去如代码10.9所展示的。

  1. abstract class Element {  
  2.  def contents: Array[String]  
  3.  def width: Int =  
  4.   if (height == 00 else contents(0).length  
  5.  def height: Int = contents.length  
  6.  def above(that: Element): Element =  
  7.   new ArrayElement(this.contents ++ that.contents)  
  8.  def beside(that: Element): Element =  
  9.   new ArrayElement(  
  10.    for (  
  11.     (line1, line2) < - this.contents zip that.contents  
  12.    ) yield line1 + line2  
  13.   )  
  14.  override def toString = contents mkString "\n" 
  15. }  

代码 10.9 带有above,beside和toString的类Element

【相关阅读】

  1. Scala学习:使用组合与继承
  2. 在Scala中定义final成员
  3. Scala程序中如何实现多态和动态绑定
  4. Scala学习:调用超类构造器和override修饰符的使用
  5. Scala:重载方法和字段及定义参数化字段

责任编辑:book05 来源: Artima
相关推荐

2009-07-21 12:18:37

ScalaRational对象toString

2009-07-22 08:52:05

Scala动态绑定

2009-07-22 09:43:30

Scala类型

2011-03-14 10:47:30

HashMap

2009-07-22 09:27:04

Scala变高变宽

2009-08-13 10:35:05

Scala数组排序

2009-06-16 17:54:38

Scala类语法语义

2009-09-09 10:50:55

Scala例子Scala与Java

2009-09-09 11:37:08

Scala的模式匹配

2009-07-22 07:49:00

Scala控制结构

2009-07-08 12:43:59

Scala ServlScala语言

2010-09-14 15:34:41

Scala

2009-07-20 16:56:51

Scala类的定义

2012-12-03 10:26:51

Scala

2020-10-31 17:33:18

Scala语言函数

2009-09-15 18:27:59

equals实现canEqualScala

2011-03-18 19:37:38

Eventable接口QtWidget

2009-07-30 10:59:44

Scala和Erlan多核

2011-06-28 11:05:19

Qt QWidget Eventable

2009-07-20 18:03:26

Scala程序Singleton对象
点赞
收藏

51CTO技术栈公众号