复合数据之一:结构体
函数的输入很少局限于单一的度量(数值),单一的开关位置(布尔值)或单一的名字(符号)。函数处理的数据通常是一个具有多个属性的对象,其中每个属性表示一种信息。例如,一个函数的输入可能是关于一张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-x
和posn-y
,前者提取x坐标,后者提取y坐标。
下述等式描述了posn-x
,posn-y
和make-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,可以快速检验新函数的计算结果是正确的。