制作这样的函数有什么区别:
fn add(_: i32) -> i32 {
10 + 25
}
还有这个
fn add() -> i32 {
10 + 25
}
我意识到第一个函数在调用时需要一个参数,即使它没有被使用,所以我认为第二个版本在这种情况下应该是可以的。
是否有任何理由允许我使用第一个版本?我在铁的例子中看到这一点,当实现一个处理程序到某个路由时。我很困惑,为什么它必须是这样的时候,提供一个空参数应该工作
函数签名是调用者和被调用者之间的契约:
- 它允许调用者确保它传递的参数是合约指定的参数
- 它允许被调用者确信它收到的参数是合约中指定的参数
而且,也许更重要的是,它强制了一个封装边界:调用方不知道被调用方读取或修改了哪些参数,它所知道的只是合约的要求。
这个封装是这里的驱动因素。这个API的设计是因为一些客户端可能会使用这个值,所以它被传递。特定的客户端是否使用它,是客户端的实现细节,调用者不会(也不应该)关心。
简短的回答:零参数的函数与一个参数的函数具有不同的API和ABI。
长答:
Iron处理器期望一个只有一个参数的函数。如果你可以传递一个没有参数的函数,Iron怎么知道呢?它指定应该有一个参数,这是API需求。即使你丢弃了这个参数也不会改变什么,Iron仍然会将这个参数传递给函数。
如果你(不安全地)传递一个没有参数的函数,那么Iron仍然会传递那个参数,但是函数的代码不需要参数,这样你就引入了未定义的行为。
也就是说,Iron可以提供一些辅助特性,允许您传递零参数函数,但这样做只是引入了您看不到的第二层:
fn short_add() -> i32 {
add(42) // or another dummy value
}
不同签名的函数是不可互换的,因为ABI是不同的。
虽然你可能认为忽略参数没有什么区别,但你不能依赖它;在某些情况下,这确实很重要。例如,任何带有析构函数的函数都希望被调用函数在返回前销毁形参。
Rust的优势之一是它的强类型系统,默认情况下不允许这样的错误使用(类似于整数转换等);在这个特殊的例子中,添加未命名/未使用的参数是很容易的,所以不是很不方便。
在Rust中,可以传递函数指针和闭包,但是具有不同参数和返回值的函数具有不同的类型。
的例子:
fn test_no_args(f0: fn() -> i32) {
println!("{}", f0())
}
fn test_1_arg(f1: fn(i32) -> i32) {
println!("{}", f1(3))
}
fn main() {
// test function with no args
fn t0() -> i32 {
42
}
// test func with 1 arg
// we're discarding the arg
// but we need this signature to call test_1_arg
fn t1(_: i32) -> i32 {
3
}
test_no_args(t0);
test_1_arg(t1);
// test_no_args(t1); doesn't compile, test_no_args expects a fn() -> i32
}
注意test_1_arg
是如何期望fn(i32)-> i32
的,但我们想给它提供我们的t1函数,它并不真正需要输入。
第一个函数意味着我有函数add
,但函数本身说我不在乎它是什么。
但是第二个表示我不需要任何参数。它们彼此不兼容。
铁框架需要一个函数,它将提供一个参数给它。框架并不关心你是否使用了参数