函数的基本概念
现在我们已经介绍了函数是什么以及它们的一些基本功能,让我们更仔细地看看为什么它们很有用。
为什么要使用函数?
新程序员经常问,“我们不能把所有代码都放在主函数里吗?” 对于简单的程序,你完全可以这么做。然而,函数提供了许多好处,使得它们在非平凡长度或复杂性的程序中非常有用。
组织性优势
组织性 —— 当程序复杂性增加时,所有代码都放在main()函数内变得越来越复杂。函数几乎就像是一个我们可以独立于主程序编写的迷你程序,编写时不需要考虑程序的其他部分。这使我们能够将复杂的程序分解成更小、更易于管理的部分,从而降低了程序的整体复杂性。
可重用性优势
可重用性 —— 一旦函数被编写,它可以在程序中被多次调用。这避免了重复代码(“不要重复自己”)并最小化了复制/粘贴错误的可能性。函数也可以与其他程序共享,减少了每次从头开始编写(和重新测试)代码的数量。
测试便利性
测试 —— 因为函数减少了代码冗余,所以最初需要测试的代码就少了。也因为函数是自包含的,一旦我们测试了一个函数以确保它工作正常,除非我们改变了它,否则我们不需要再次测试它。这减少了我们一次需要测试的代码量,使得查找错误(或从一开始就避免它们)变得更加容易。
可扩展性优势
可扩展性 —— 当我们需要扩展我们的程序以处理它之前没有处理过的案例时,函数允许我们在一个地方进行更改,并让这个更改在每次调用函数时生效。
抽象性优势
抽象性 —— 为了使用一个函数,你只需要知道它的名称、输入、输出以及它的位置。你不需要知道它是如何工作的,或者它依赖于什么其他代码才能使用它。这降低了使用他人代码(包括标准库中的所有内容)所需的知识量。
有效使用函数的指南
新程序员遇到的最大的挑战之一(除了学习语言)是理解何时以及如何有效地使用函数。以下是编写函数的一些基本指导方针:
重复代码的函数化
在程序中多次出现的语句组通常应该被制作成函数。例如,如果我们多次以相同的方式从用户那里读取输入,那是一个很好的函数候选。如果我们在多个地方以相同的方式输出某物,那也是一个很好的函数候选。
明确输入输出的函数化
具有明确输入和输出集的代码是函数的好候选(特别是如果它很复杂)。例如,如果我们有一个我们想要排序的项目列表,排序代码将是一个很棒的函数,即使它只做一次。输入是未排序的列表,输出是排序后的列表。另一个好的潜在函数是模拟掷一个六面骰子的代码。你当前的程序可能只在一个地方使用它,但如果将其变成一个函数,如果你以后扩展你的程序或在未来的程序中,它就准备好被重用了。
单一职责原则
函数通常应该执行一个(且只有一个)任务。
代码重构
当一个函数变得太长、太复杂或难以理解时,它可以被分割成多个子函数。这被称为重构。我们在课程3.10 —— 在问题成为问题之前发现问题中更多地讨论重构。
实际应用示例
通常,在学习C++时,你会编写很多涉及3个子任务的程序:
- 从用户那里读取输入
- 根据输入计算一个值
- 打印计算出的值
对于微不足道的程序(例如少于20行代码),这些中的一些或全部可以在main函数中完成。然而,对于更长的程序(或只是为了练习),每一个都是一个很好的单独函数候选。
常见函数设计错误
新程序员经常将计算一个值和打印计算出的值合并到一个单一函数中。然而,这违反了函数的"一个任务"规则。计算一个值的函数应该将值返回给调用者,并让调用者决定如何处理计算出的值(例如,调用另一个函数来打印值)。