5.1 函数的作用

    在第 4 章中,我们学习了 if 语句、for 语句、while 语句等产生的原因。本章我们来学习函数,即把代码的一部分视作有机整体,然后切分出来并为之命名的程序设计机制 1。

    1这种机制在不同时期和不同语言中,有事务、程序(procedure)、子程序(subroutine)等不同的叫法。但大多数人都习惯称它为“函数”。另外,类似的机制还有方法(method)。关于这个我们会在第 11 章讲解,这里我们为简单起见,将函数和方法等同视之。

    函数为什么必不可少呢?有没有因为没有函数而不能编写的程序呢?答案是否定的。尽管没有函数也可以编写程序,但使用函数编写程序将变得更轻松简便:因为它便于理解和重复使用。

    便于理解——如同一个组织

    把代码切分为多个函数,如同将一个大的组织按部门划分开。在一个小的程序中,函数的优越性体现不出来,这和没必要把几个关系融洽的人组成一个部门让大家互相熟悉是一个道理。人数很少的话,圈子里的每个人都熟知其他人的姓名、长相和特长。同样,代码数很少的情况下,很容易就能把握每一行执行什么功能。

    问题是,人数一旦多起来怎么办。这样一来,把握方方面面的事情变得越来越困难。因此,可以把某些人视作一个单独的小组并为这个小组取个名字,比如财务部、某开发组等。

    程序设计上也一样。源代码的行数多起来后要把握整体就变得困难起来。因此,把一定行数的代码视作一个整体并为之取名,这就是函数。

    便于再利用——如同零部件

    构建函数类似于将小的零部件组合起来制造大的零部件。比如,无线遥控玩具车里有碱性电池和电机,把碱性电池和电机放到指定的位置,就能把玩具车组装起来。

    事实上,电机中还包含线圈、磁铁和整流子 2,而碱性电池中有二氧化猛、锌和氢氧化钾。

    2这是电机中非常重要的零部件之一,它通过切换线圈中电流的方向保证线圈持续地朝一个方向旋转。

    要无线遥控玩具车,当然首先要制作电机和电池。为此,就要理解电机是如何将电流转化成旋转运动以及电池中发生了怎样的化学反应从而产生了电。现实中,把二氧化猛、锌和氢氧化钾配置包装起来并销售的东西已经存在,那就是碱性电池,在便利店等地方很容易就能买到。电机也能在塑料模型用品店里轻松买到。

    函数也一样。将数十行、数百行代码作为函数,通过简单地调用就能使用它的功能 3。

    3也许有人说,不理解其中内容就拿来使用不太好。这种看法是可以理解的,但与本文论述无关,这里不作讨论。

    另外,电池这一命名方式有助于理解使用了电池的系统功能。即使不知道电池内部的详细结构与工作原理,只要知道“电池就是能产生电的东西”这一点,小学生也能组装无线遥控玩具车。并且,玩具车一旦行驶缓慢就会让人想到是不是电池快没电了。这个道理和函数有助于理解程序是类似的。

    程序中再利用的特征

    编写程序和制造物理实体有一个很大的区别,那就是重复使用零部件时所产生的成本的类型。

    看个例子,假如要为整栋公寓楼所有房间的水龙头安装净水器,公寓楼有 100 个房间的话就需要配备 100 个净水器,相应地,有 200 个房间的话就要 200 个净水器。房间数量越多,所耗费的资金和空间资源也就越多。

    我们再回到程序中,假如要用某个函数来处理列表中所有的数据,有 100 个数据的话就要调用此函数 100 次,有 200 个的话就要调用 200 次。数据量越多,所需的执行时间也就越长。但是,函数的实现只需一个就足够了,调用 200 次并不需要将此函数实现 200 次。通过把需要反复执行的操作封装成函数,进而多次调用,可以确保源代码紧凑且清晰。

    把相同的操作封装在一起的好处不仅仅在于使程序更简短,也在于能使阅读程序的人无需反复读取相同内容的源代码。从冗长的程序中切分出反复使用的代码将其封装成一个整体,程序就更容易理解了。