函数 · 14
函数
给一段工作起名字,接收值并返回结果,还有递归。
函数是有名字的一段代码。
它接收值(参数),并返回结果。
下面的示例定义了一个求平方的函数,和一个调用自己的阶乘函数。
def square(x): return x * x def factorial(n): if n <= 1: return 1 return n * factorial(n - 1) n = int(input())print(square(n))print(factorial(n))function square(x) { return x * x;} function factorial(n) { if (n <= 1) return 1; return n * factorial(n - 1);} const n = Number(require("fs").readFileSync(0, "utf8"));console.log(square(n));console.log(factorial(n));import { readFileSync } from "node:fs"; function square(x: number): number { return x * x;} function factorial(n: number): number { if (n <= 1) return 1; return n * factorial(n - 1);} const n: number = Number(readFileSync(0, "utf8"));console.log(square(n));console.log(factorial(n));import java.util.Scanner; public class Main { static int square(int x) { return x * x; } static long factorial(int n) { if (n <= 1) return 1; return n * factorial(n - 1); } public static void main(String[] args) { int n = new Scanner(System.in).nextInt(); System.out.println(square(n)); System.out.println(factorial(n)); }}using System; class Program{ static int Square(int x) => x * x; static long Factorial(int n) { if (n <= 1) return 1; return n * Factorial(n - 1); } static void Main() { int n = int.Parse(Console.ReadLine()); Console.WriteLine(Square(n)); Console.WriteLine(Factorial(n)); }}#include <iostream> int square(int x) { return x * x;} long long factorial(int n) { if (n <= 1) return 1; return n * factorial(n - 1);} int main() { int n; std::cin >> n; std::cout << square(n) << '\n'; std::cout << factorial(n) << '\n';}#include <stdio.h> int square(int x) { return x * x;} long long factorial(int n) { if (n <= 1) return 1; return n * factorial(n - 1);} int main(void) { int n; scanf("%d", &n); printf("%d\n", square(n)); printf("%lld\n", factorial(n)); return 0;}square(x){ 返回 x * x;} factorial(n){ 如果 (n <= 1) { 返回 1; } 返回 n * factorial(n - 1);} n = 控制台.读行().转数字();控制台.输出(square(n));控制台.输出(factorial(n));4
16 24
要点
- 同一个计算要在多处使用,或者想把长的解法拆成小块时,就把代码包成函数。
- 一执行到
return,函数就当场结束,下面的行不会执行。 - 传数字时会复制值。
在函数里写x = 9,调用方的变量不变。 - 传列表时共用同一个列表。
在函数里添加元素,外面也会跟着变(C++ 的vector传参时会复制)。 - 递归就是函数调用自己。
它把大问题缩小成同样形状的小问题,而且一定要有停止条件(n <= 1时返回1)。 - 没有停止条件或递归太深时,程序会报错停止或直接崩溃,取决于语言。
各语言的写法
| Python | def square(x): 加缩进。没有 return 时返回 None。只能在 def 执行之后调用(先调用报 NameError)。递归默认约 1,000 层时报 RecursionError |
|---|---|
| JavaScript | function square(x) { return x * x; } 或 const square = (x) => x * x;。没有 return 时返回 undefined。function 声明可以写在调用处下面。太深报 RangeError: Maximum call stack size exceeded |
| TypeScript | JavaScript 加上类型:function square(x: number): number。参数个数不对时类型检查会提示 |
| Java | 在类里写 static int square(int x);不返回值写 void。放在类里任何位置都行。 太深报 StackOverflowError |
| C# | 和 Java 一样在类里写 static int Square(int x),不返回值写 void。递归太深会让整个程序崩溃 |
| C++ | 像 int square(int x) 这样把返回类型写在前面,不返回值写 void。使用前先在上面定义,或用 int square(int x); 声明。递归太深程序会崩溃 |
| C | 和 C++ 一样 |
| Craykon | 不需要关键字:square(x) { 返回 x * x; }。可以写在调用处下面。 调用超过几千层会停止,并提示函数调用得太深 |
常见错误
没有停止条件
def factorial(n):
return n * factorial(n - 1)→ 无限调用自己,最后报 RecursionError 停止。其他语言也会栈溢出而停止或崩溃
在最前面放停止条件,比如 if n <= 1: return 1。
调用时漏了参数JavaScript
function square(x) { return x * x; }
console.log(square());→ NaN — 缺少的 x 被悄悄补成了 undefined
参数个数要对上。
Python(TypeError)、Java、C#、C、C++、TypeScript(编译错误)和 Craykon(“需要 2 个值却只给了 1 个”)都会提示。
在函数里改了,原来的却没变C++
void add(std::vector<int> v) { v.push_back(9); }
std::vector<int> a = {1};
add(a);→ a 仍然是 {1} — 加到了副本里
要修改原来的,就加 &:std::vector<int>& v。
各语言的差异
阶乘增长得很快。
32 位
阶乘增长得很快。
32 位
int 只能装到 12!(在 Java 中用 int 算 13! 会不报错地得到 1932053504),所以 Java、C#、C、C++ 示例返回 64 位的 long/long long(可到 20!),而 Python 没有大小限制,JavaScript 和 Craykon 超过 2^53 后可能不精确。