复合数据之一:结构体

函数的输入很少局限于单一的度量(数值),单一的开关位置(布尔值)或单一的名字(符号)。函数处理的数据通常是一个具有多个属性的对象,其中每个属性表示一种信息。例如,一个函数的输入可能是关于一张CD的记录,相关的信息可能包括艺术家的名字,CD的标题和CD的价格。类似地,如果要使用函数来刻画平面上一个物体的运动,则必须表示物体在平面上的位置,每个方向上的速度,可能的话,还有物体的颜色,等等。在这两种情况下,谈到几种信息时就好像它们是一个对象:一个记录或平面上的一个点。简而言之,可以将几种类型的数据组合为一种数据。

Scheme提供了多种不同的数据组合方法。本章讨论结构体,结构体将固定数目的值组合为单一数据.本站讨论结构体,结构体将固定数目的值组合为单一数据。第9章将讨论把任意数目的数据组合为单一数据的方法。

结构体

假设要在计算机屏幕上表示像素,像素类似于笛卡尔点,它有一个x坐标,表示像素在水平方向上的位置,有一个y坐标,表示像素在垂直方向上的位置,给定两个数值,就可以确定屏幕上的一个像素。

在DrScheme的教学软件包中,像素是一个posn结构体,包含两个数值,也可以说posn结构体是包含两个数的一个整体。使用操作make-posn创建一个posn结构体,该操作的输入是两个数值,输出是类型为posn的一个结构体。如:

(make-posn 3 4)
(make-posn 8 6)
(make-posn 5 12)

考虑计算给定像素和原点距离的函数,函数的合约,头部和用途说明可以简单地阐述为:

;; distance-to-0 : posn -> number
;; 计算一个posn和原点的距离
(define (distance-to-0 a-posn) ...)

可以看出distance-to-0的输入为一个简单的值,一个posn结构体,结果也是一个简单的值,即数。

对于例子,输入可以是上面提到的3个posn结构体,目前所需要的是输入与输出相联系的例子。显而易见,如果0是坐标之一,则函数结果就是另一个坐标值:

  (distance-to-0 (make-posn 0 5))
= 5

  (distance-to-0 (make-posn 7 0))
= 7

一般来说,可以根据勾股定理求出坐标为x和y的点离原点的距离。因此,

  (distance-to-0 (make-posn 3 4))
= 5

  (distance-to-0 (make-posn 8 6))
= 10

  (distance-to-0 (make-posn 5 12))
= 13

现在,将注意力转向函数的定义。虽然例子说明distance-to-0的设计不需要区分不同的情况。但我们还是束手无策,因为distance-to-0的单个参数表示的是整个像素,而计算距离却需要两个坐标的值。从另一个角度来说,我们知道如何使用make-posn将两个数值组合为一个posn结构体,但是不知道如何从一个posn结构体中提取这些数值。

幸运的是,Scheme提供了从结构体中提取值的操作。对于posn结构体,有两个操作:posn-xposn-y,前者提取x坐标,后者提取y坐标。

下述等式描述了posn-x,posn-ymake-posn之间的关系:

  (posn-x (make-posn 7 0))
= 7

  (posn-y (make-posn 7 0))
= 0

现在已经有了定义`distance-to-0所需要的所有知识:函数的a-posn参数是一个posn结构体,该结构体包含了两个数值,可以使用(posn-x a-posn)(posn-y a-posn)`提取它们。将这些知识加到函数定义框架之中,有:

(define (distance-to-0 a-posn)
  ... (posn-x a-posn) ...
  ... (posn-y a-posn) ...)

使用框架和例子,函数其余部分的定义就容易了:

(define (distance-to-0 a-posn)
  (sqrt
    (+ (sqr (posn-x a-posn))
        (sqr (posn-y a-posn)))))

函数先分别计算(posn-x a-posn)(posn-y a-posn),即坐标x和y,再求平方和,最后求平方根。使用DrScheme,可以快速检验新函数的计算结果是正确的。

Loading Disqus comments...
Table of Contents