函数
函数在 X 语言中无处不在。虽然 main 函数是许多程序的入口点,但请记住,在 X 语言中 main 函数不是必须的——你可以直接在文件顶层编写代码!你也见过 function 关键字,它用于声明一个新函数。
X 语言代码使用蛇形命名法(snake_case)作为函数和变量名的规范风格。在蛇形命名法中,所有字母都是小写的,并使用下划线分隔单词。
定义函数
让我们编写一个调用另一个函数的程序,不使用 main 函数:
println("Hello, world!")
another_function()
function another_function() {
println("另一个函数。")
}
在 X 语言中,我们通过输入 function 关键字,后跟函数名和一组圆括号来定义函数。大括号告诉编译器函数体从哪里开始和结束。
我们可以通过使用函数名后跟一组圆括号来调用我们已定义的任何函数。请注意,我们在源文件中先定义了 another_function 后才调用它;我们也可以先调用后定义。X 语言不关心你在哪里定义函数,只关心它们在调用者可以看到的作用域中的某个地方被定义。
让我们创建一个名为 functions.x 的新文件,并把上面的代码放进去。运行它,你应该会看到以下输出:
Hello, world!
另一个函数。
函数参数
函数也可以被定义为具有参数,参数是作为函数签名一部分的特殊变量。当一个函数有参数时,你可以在调用该函数时为这些参数提供具体值。从技术上讲,具体值被称为参数,但在日常对话中,人们倾向于将参数和参数这两个词互换使用,用于函数定义中的变量或调用函数时传入的具体值。
在这个版本的 another_function 中,我们添加了一个参数:
another_function(5)
function another_function(x: integer) {
println("x 的值是: ", x)
}
尝试运行这个程序;你应该会得到以下输出:
x 的值是: 5
让我们仔细看看 another_function 定义的这一部分。首先,我们有一个参数 x。在参数名后面,我们必须添加一个冒号 :,然后是参数的类型。在 X 语言中,必须在函数签名中声明每个参数的类型,这是经过深思熟虑的设计决策:在函数定义中要求类型注解意味着编译器几乎从不需要你在代码的其他地方使用它们来推断你的意思。
当一个函数有多个参数时,用逗号分隔它们,如下所示:
print_labeled_measurement(5, 'h')
function print_labeled_measurement(value: integer, unit_label: character) {
println("测量值是: ", value, unit_label)
}
这个例子创建了一个名为 print_labeled_measurement 的函数,它有两个参数。第一个参数名为 value,类型是 integer。第二个名为 unit_label,类型是 character。然后函数打印包含这两个值的文本。
让我们尝试运行这段代码。用上面的例子替换 functions.x 文件中的程序,然后用 x run functions.x 运行它:
测量值是: 5h
包含语句和表达式的函数体
函数体由一系列语句组成,可选地以一个表达式结束。到目前为止,我们只看到了没有结束表达式的函数,但你已经将表达式作为语句的一部分看到了。
语句是执行某些操作但不返回值的指令。表达式计算结果为一个值。让我们看几个例子:
let x = 5是一个语句5 + 6是一个计算为11的表达式- 调用函数是一个表达式
- 调用宏是一个表达式
- 我们用来创建新作用域的块
{ }是一个表达式
例如:
let y = {
let x = 3
x + 1
}
println("y 的值是: ", y)
块 { let x = 3; x + 1 } 是一个计算为 4 的表达式。然后该值被绑定到 y 作为 let 语句的一部分。请注意,x + 1 行末尾没有分号,这与你到目前为止看到的大多数行不同。表达式不包含结尾分号。如果在表达式末尾添加分号,则会将其变成语句,然后它将不会返回值。在探索函数返回值和表达式时请记住这一点。
带有返回值的函数
函数可以向调用它们的代码返回值。我们不给返回值命名,但我们必须在箭头 -> 之后声明它们的类型。在 X 语言中,函数的返回值与函数体块中的最终表达式的值同义。你可以使用 return 关键字并指定一个值从函数提前返回,但大多数函数隐式返回最后的表达式。这是一个返回值的函数的示例:
function five() -> integer {
5
}
let x = five()
println("x 的值是: ", x)
让我们更仔细地研究一下这段代码。首先,看一下 five 函数:它以 -> integer 结尾,这意味着它将返回一个 integer 值。请注意,我们也可以在函数体的最后一行使用 return 5,但 5 本身作为表达式也是可以的。
let x = five(); 这一行表示我们将使用函数的返回值来初始化变量 x。因为 five 返回 5,所以这一行与 let x = 5; 相同。
让我们运行这段代码;输出应该如下所示:
x 的值是: 5
这是另一个例子:
function plus_one(x: integer) -> integer {
x + 1
}
let x = plus_one(5)
println("x 的值是: ", x)
运行这段代码将打印 x 的值是: 6。但是如果我们在包含 x + 1 的行末尾放置一个分号,将其从表达式改为语句,我们会得到一个错误:
function plus_one(x: integer) -> integer {
x + 1; // 错误:这里需要表达式,不能有分号
}
let x = plus_one(5)
println("x 的值是: ", x)
这个错误说明函数期望返回一个 integer,但没有返回值。实际上,如果我们使用分号,函数会隐式返回 Unit(也写作 ())。
Unit 类型作为返回值
如果一个函数没有指定返回类型,它隐式返回 Unit 类型。Unit 是一个只有一个可能值的特殊类型,也写成 ()。当没有其他有意义的值可以返回时,就会使用 Unit。
示例:
function do_something() {
println("做了一些事情")
// 隐式返回 Unit
}
let result = do_something()
println("结果是: ", result) // 会打印 "结果是: Unit"
总结
函数是 X 语言编程的基础部分。让我们回顾一下关于函数的知识:
- 使用
function关键字定义函数 - 函数名使用蛇形命名法(snake_case)
- 必须为每个参数声明类型
- 使用
-> Type声明返回类型 - 函数体中的最后一个表达式是返回值
- 可以使用
return关键字提前返回 - 没有显式返回类型的函数返回
Unit main函数不是必须的——你可以直接在文件顶层编写代码
接下来,让我们看看注释!