Rust 中的字符串相等性:引用和取消引用如何工作?
String equality in Rust: how does referencing and dereferencing work?
作为 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());
}
}
为了将这些产品过滤成回文产品,我有以下两种解决方案:
解决方案一:
let palindromes: Vec<_> = products
.iter()
.filter(|&x| x == &x.chars().rev().collect::<String>())
.collect();
方案二:
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
而不在我的过滤器函数中引用或取消引用它?
谢谢!
Vec<String>.iter()
returns 对引用 (&String
) 的迭代器。
.filter()
的闭包参数引用了迭代器的项。所以传递给闭包的类型是双引用 &&String
.
|&x|
告诉闭包期待一个引用,所以 x
现在是 &String
. 类型
第一个方案:collect
returns一个String
,其中&
取参考。 x
也是对字符串的引用,所以比较的是两个&String
.
第二种解决方案:取消引用运算符 *
应用于 x
,结果是 String
。右侧很有趣:collect
的 String
结果被取消引用。这会导致字符串切片,因为标准库中的 String
implements Deref<Target=str>
. Now the comparison is between String
and str
, which is works because it is implemented(请注意,a == b
等同于 a.eq(&b)
)。
第三种解决方案:编译器解释为什么它不起作用。
the trait std::cmp::PartialEq<std::string::String>
is not implemented for &&std::string::String
左边是对字符串 (&&String
) 的双重引用,右边只是一个 String
。 你需要让双方都一样 "reference level"。 所有这些工作:
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>());
作为 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());
}
}
为了将这些产品过滤成回文产品,我有以下两种解决方案:
解决方案一:
let palindromes: Vec<_> = products
.iter()
.filter(|&x| x == &x.chars().rev().collect::<String>())
.collect();
方案二:
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
而不在我的过滤器函数中引用或取消引用它?
谢谢!
Vec<String>.iter()
returns 对引用 (&String
) 的迭代器。.filter()
的闭包参数引用了迭代器的项。所以传递给闭包的类型是双引用&&String
.|&x|
告诉闭包期待一个引用,所以x
现在是&String
. 类型
第一个方案:collect
returns一个String
,其中&
取参考。 x
也是对字符串的引用,所以比较的是两个&String
.
第二种解决方案:取消引用运算符 *
应用于 x
,结果是 String
。右侧很有趣:collect
的 String
结果被取消引用。这会导致字符串切片,因为标准库中的 String
implements Deref<Target=str>
. Now the comparison is between String
and str
, which is works because it is implemented(请注意,a == b
等同于 a.eq(&b)
)。
第三种解决方案:编译器解释为什么它不起作用。
the trait
std::cmp::PartialEq<std::string::String>
is not implemented for&&std::string::String
左边是对字符串 (&&String
) 的双重引用,右边只是一个 String
。 你需要让双方都一样 "reference level"。 所有这些工作:
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>());