有没有一种方法可以显式地编写闭包的类型?

10
我开始阅读有关闭包的Rust指南。来自该指南的内容如下:

这是因为在Rust中,每个闭包都有其独特的类型。因此,不仅具有不同签名的闭包具有不同类型,而且具有相同签名的不同闭包也具有不同类型。

是否有一种方法可以显式地编写闭包的类型签名?是否有任何编译器标志可以扩展推断闭包的类型?
2个回答

9

不行。一个闭包的真正类型只有编译器知道,而且知道给定闭包的具体类型其实并没有太大用处。但是,您可以指定某些闭包必须符合的“形状”:

fn call_it<F>(f: F)
where
    F: Fn(u8) -> u8, // <--- HERE
{
    println!("The result is {}", f(42))
}

fn main() {
    call_it(|a| a + 1);
}

在这种情况下,我们称call_it接受任何实现了具有一个类型为u8的参数和返回类型为u8的特质Fn的类型。然而,许多闭包和自由函数都可以实现该特质。
从Rust 1.26.0开始,您还可以使用impl Trait语法来接受或返回闭包(或任何其他特质)。
fn make_it() -> impl Fn(u8) -> u8 {
   |a| a + 1
}

fn call_it(f: impl Fn(u8) -> u8) {
    println!("The result is {}", f(42))
}

fn main() {
    call_it(make_it());
}

1
引用参考文献:“闭包表达式生成一个具有唯一匿名类型的闭包值,该类型无法写出”。
然而,在RFC1558定义的条件下,闭包可以被强制转换为函数指针。
let trim_lines: fn((usize, &str)) -> (usize, &str) = |(i, line)| (i, line.trim());

函数指针可以像常规函数一样在.map().filter()等中使用。类型可能不同,但返回值将具有Iterator特质。


1
这是不正确的。函数指针和闭包并不相同。函数指针通常可以强制转换为闭包,但并非总是如此。每当您尝试使用捕获了非 Copy + Clone 变量的闭包进行此操作时,您会发现它会抛出错误。 - CATboardBETA
1
@CATboardBETA 你可以注意到,我从未声称函数指针和闭包是相同的。然而,这是一个非常好的观察,不是所有的闭包都可以强制转换为函数指针。我会更新我的答案来传达这些限制。 - Dmitrii Demenev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接