制作这样的函数有什么区别:
fn add(_: i32) -> i32 {
10 + 25
}
这一个:
fn add() -> i32 {
10 + 25
}
我意识到第一个函数在被调用时需要一个参数,即使它没有被使用,所以我认为在这种情况下第二个版本应该没问题。
为什么我被允许使用第一个版本?我在Iron的例子中看到了这一点,当时为某条路线实现了一个处理程序。我很困惑为什么在提供空参数应该有效时必须这样做。
答案 0 :(得分:5)
函数签名是调用者和被调用者之间的契约:
而且,更重要的是,它强制执行封装边界:调用者不知道被调用者读取或修改了哪些参数,它只知道合同需要的内容。
这种封装是驱动因素。设计API是因为某些客户端可能会使用此值,因此会传递它。 特定客户端是否使用它是客户端的实现细节,并且调用者不会(也不应该)关心。
答案 1 :(得分:2)
简短回答:零参数的函数与具有一个参数的函数具有不同的API和ABI。
答案很长:
Iron处理程序需要一个带有一个参数的函数。如果你能够传递一个没有参数的函数,Iron会怎么知道呢?它指定应该有一个参数,以便API要求。抛弃参数的事实不会改变任何东西,Iron仍会将该参数传递给函数。
如果你(不安全地)传递一个零参数的函数,那么Iron仍然会传递那个参数,但函数的代码并不期望参数,因此你会引入未定义的行为
也就是说,Iron可以提供一些辅助特质魔法,允许你传递零参数函数,但所有这一切都会引入你不会看到的第二层:
fn short_add() -> i32 {
add(42) // or another dummy value
}
答案 2 :(得分:1)
具有不同签名的功能不可互换,因为ABI不同。
虽然你可能认为如果你忽略了这个参数并没有什么不同,你就不能依赖它;并且确实存在重要的情况。例如,任何带有析构函数的东西都会期望被调用的函数在返回之前销毁该参数。
Rust的优势之一是它强大的类型系统,默认情况下不允许这样的错误使用(类似的整数转换等);在这种特殊情况下,添加未命名/未使用的参数非常容易,因此不会非常不方便。
答案 3 :(得分:1)
在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函数。
答案 4 :(得分:-1)
第一个函数意味着我有函数add
,但函数本身说我不在乎它是什么。
但第二个意味着我不需要任何参数。它们彼此不相容。
铁框架需要一个函数,它将为它提供一个参数。框架并不关心你是否使用参数。