filter(|x|)和filter(|&x|)有什么区别?(涉及IT技术)

7
在 Rust 语言手册中有一个调用迭代器的 filter() 函数的示例: Rust Book
for i in (1..100).filter(|&x| x % 2 == 0) {
    println!("{}", i);
}

下面有一段解释,但我很难理解:

这将打印出1到100之间的所有偶数。(请注意,由于filter不会消耗正在迭代的元素,因此它会传递对每个元素的引用,因此过滤谓词使用&x模式来提取整数本身。)

然而,这并不起作用:

for i in (1..100).filter(|&x| *x % 2 == 0) {
    println!("i={}", i);
}

闭包的参数为什么是一个引用 |&x|,而不是 |x|?使用 |&x||x| 有什么区别?
我知道使用引用 |&x| 更高效,但我对于不需要使用 *x 对指针 x 进行解引用感到困惑。
1个回答

8
在用作模式匹配时(闭包和函数参数也是模式匹配),&将绑定到一个引用,使变量成为取消引用的值。
fn main() {
    let an_int: u8 = 42;
    // Note that the `&` is on the right side of the `:`
    let ref_to_int: &u8 = &an_int; 
    // Note that the `&` is on the left side of the `:`
    let &another_int = ref_to_int;
    let () = another_int;
}

出现错误:

error: mismatched types:
 expected `u8`,
    found `()`

如果你查看你的错误信息,它会指出你无法对其进行取消引用,因为它不是一个引用:

error: type `_` cannot be dereferenced

我不需要使用 *x 解引用 x 指针。

这是因为你在模式匹配中隐式地解引用了它。

我知道使用引用 |&x| 更有效率。

如果这是真的,那么就没有理由使用除了引用以外的任何东西了!也就是说,引用需要额外的间接寻址才能得到真正的数据。有一些可测量的临界点,在这个点之前通过值传递项比通过引用传递它们更有效率。

如果是这样,那么为什么使用 |x| 不会抛出错误?根据我在 C 中的经验,我会期望在这里收到一个指针。

而你确实会收到一个指针,以引用的形式。在这个例子中,x 是一个指向 i32 的引用。然而,% 运算符是由特性 Rem 提供的,这个特性对所有的引用 / 值对都进行了实现:

impl Rem<i32> for i32
impl<'a> Rem<i32> for &'a i32
impl<'a> Rem<&'a i32> for i32
impl<'a, 'b> Rem<&'a i32> for &'b i32

这使您不需要显式地对其进行解引用。
或者Rust在此处隐式在堆栈上分配了原始x值的副本吗?
它绝对没有这样做。事实上,这样做是不安全的,除非迭代项实现了Copy(或潜在的Clone,在这种情况下可能也很昂贵)。这就是为什么引用被用作闭包参数的原因。

那么 let &x = my_pointer 实际上是 let x = *my_pointer 的另一种写法,而且它也适用于函数参数声明吗?如果是这样的话,为什么使用 |x| 不会抛出错误?根据我在 C 中的经验,我希望在这里收到一个指针。或者 Rust 在这里隐式地在堆栈上分配了原始 x 值的副本吗? - jeremija
哦,我还有很多东西要学习 :) 谢谢 - 现在对我来说更清晰了! - jeremija

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