6

作为一名 Rust 新手,我正在解决Project Euler问题,以帮助我了解这门语言。问题 4 涉及回文,我找到了两个用于创建回文向量的解决方案,但我不确定它们中的任何一个是如何工作的。

我正在使用一个字符串向量products,它是这样计算的:

let mut products = Vec::new();
for i in 100..500 {
    for j in 500..1000 {
        products.push((i * j).to_string());
    }
}

为了将这些产品过滤到只有回文的产品,我有以下两种解决方案:

解决方案1:

let palindromes: Vec<_> = products
    .iter()
    .filter(|&x| x == &x.chars().rev().collect::<String>())
    .collect();

解决方案2:

let palindromes: Vec<_> = products
    .iter()
    .filter(|&x| *x == *x.chars().rev().collect::<String>())
    .collect();

他们都产生了正确的结果,但我不知道为什么!

在解决方案 1 中,我们将字符串的引用与我们刚刚创建的字符串的引用进行比较?

在解决方案 2 中,我们取消引用对字符串的引用并将其与取消引用的新字符串进行比较?

我希望能够做到的事情:

let palindromes: Vec<_> = products
    .iter()
    .filter(|x| x == x.chars().rev().collect::<String>())
    .collect();

我希望有人能够向我解释:

  • 我的两种解决方案有什么区别,为什么它们都有效?
  • 为什么我不能x在我的过滤器函数中不引用或取消引用它就使用它?

谢谢!

4

1 回答 1

10
  1. Vec<String>.iter()返回引用 ( ) 的迭代器&String
  2. 的闭包参数.filter()引用迭代器的项。所以传递给闭包的类型是双重引用&&String
  3. |&x|告诉闭包期待一个引用,所以x现在是 type &String

第一个解决方案:collect返回 a String,其中&接受引用。x也是对字符串的引用,所以比较是在两个&String.

第二种解决方案:将取消引用运算符*应用于x,这会导致String. 右边很有趣:String结果collect被取消引用。这会产生一个字符串切片,因为StringimplementsDeref<Target=str> . 现在比较是在String和之间str,这是有效的,因为它是在标准库中实现的(注意它a == b等同于a.eq(&b))。

第三种解决方案:编译器解释为什么它不起作用。

该特征std::cmp::PartialEq<std::string::String>未实现&&std::string::String

左边是对 string( &&String) 的双重引用,右边只是一个String. 您需要使双方达到相同的“参考水平”。所有这些工作:

x.iter().filter(|x| x == &&x.chars().rev().collect::<String>());
x.iter().filter(|x| *x == &x.chars().rev().collect::<String>());
x.iter().filter(|x| **x == x.chars().rev().collect::<String>());
于 2018-05-02T12:22:49.140 回答