【问题标题】:String equality in Rust: how does referencing and dereferencing work?Rust 中的字符串相等:引用和取消引用如何工作?
【发布时间】:2018-10-12 12:14:16
【问题描述】:

作为 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 而不在我的过滤器函数中引用或取消引用它?

谢谢!

【问题讨论】:

  • "它们都产生了正确的结果,但我不知道为什么!" => “理论是你什么都知道,但没有人知道为什么实践是一切都有效,但没有人知道为什么在我们的实验室中,理论和实践相结合,没有人知道为什么”
  • 我认为这与How to iterate over an array? 非常相似(尽管标题很差)。这个问题的答案是否清楚?
  • 注意不需要分配String,可以比较迭代器:.filter(|x| x.chars().eq(x.chars().rev()))
  • @piercebot 很好,Project Euler 也是我开始 rust 的方式。我可以挑战你提出一个不需要分配的回文检查(collect 在堆上创建一个新的String)吗? :)
  • 嗯.. 挑战太多了:p

标签: string rust dereference borrowing


【解决方案1】:
  1. Vec&lt;String&gt;.iter() 在引用上返回一个迭代器 (&amp;String)。
  2. .filter() 的闭包参数采用对迭代器项的引用。所以传递给闭包的类型是双重引用&amp;&amp;String
  3. |&amp;x| 告诉闭包期待一个引用,所以 x 现在是 &amp;String 类型。

第一个解决方案:collect 返回一个String,其中&amp; 获取引用。 x 也是对字符串的引用,所以比较的是两个&amp;String

第二种解决方案:将取消引用运算符* 应用于x,从而产生String。右边很有趣:collectString 结果被取消引用。这会产生一个字符串切片,因为String implements Deref&lt;Target=str&gt;。现在比较的是Stringstr,这是有效的,因为它在标准库中是implemented(注意a == b 相当于a.eq(&amp;b))。

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

特征 std::cmp::PartialEq&lt;std::string::String&gt; 没有为 &amp;&amp;std::string::String 实现

左侧是对字符串 (&amp;&amp;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>());

【讨论】:

  • 太棒了!感谢您的详尽解释!是否所有闭包参数都是默认引用,还是根据具体情况?
  • @piercebot 逐个案例。如果您查看filter 的定义,您会发现它需要一个带有&amp;Iter::Item 的闭包。相反,例如filter_map 接受的闭包采用Iter::Item,这不是参考。
猜你喜欢
  • 2016-09-28
  • 2015-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-04
相关资源
最近更新 更多