我正在编写Rust by Example教程,其中包含以下代码片段:
// Vec example
let vec1 = vec![1, 2, 3];
let vec2 = vec![4, 5, 6];
// `iter()` for vecs yields `&i32`. Destructure to `i32`.
println!("2 in vec1: {}", vec1.iter() .any(|&x| x == 2));
// `into_iter()` for vecs yields `i32`. No destructuring required.
println!("2 in vec2: {}", vec2.into_iter().any(| x| x == 2));
// Array example
let array1 = [1, 2, 3];
let array2 = [4, 5, 6];
// `iter()` for arrays yields `&i32`.
println!("2 in array1: {}", array1.iter() .any(|&x| x == 2));
// `into_iter()` for arrays unusually yields `&i32`.
println!("2 in array2: {}", array2.into_iter().any(|&x| x == 2));
我完全混淆了-对于Vec
,从iter
返回的迭代器产生引用,从返回的迭代器into_iter
产生值,但对于数组,这些迭代器是相同的?
这两种方法的用例/API是什么?
我认为有一些事情需要进一步澄清。集合类型,例如Vec
事实上,std中有一些示例:
回到关于
into_iter
和iter
之间区别的原始问题。与其他人指出的类似,区别在于into_iter
是IntoIterator
的必需方法,它可以产生IntoIterator::Item
中指定的任何类型。通常,如果一个类型实现了IntoIterator
这意味着,我们可以创建一个函数,该函数通过使用特征绑定来接收一个类型,该类型具有进入iter方法(即,它是一个iterable):
fn process_iterable<I: IntoIterator>(iterable: I) {
for item in iterable {
// ...
}
}
然而,我们不能使用一个trait绑定来要求类型具有iter方法或iter\u mut方法,因为它们只是约定。我们可以说,与iter或iter mut相比,iter的使用范围更广。
另一件有趣的事情是,iter并不是获得生成<代码>
let v = vec![1, 2];
// Below is equivalent to: `for item in v.iter() {`
for item in &v {
println!("{}", item);
}
如果v.iter()等于
let v = vec![1, 2];
let a: Vec<i32> = v.iter().map(|x| x * x).collect();
// Although above and below are equivalent, above is a lot clearer than below.
let b: Vec<i32> = (&v).into_iter().map(|x| x * x).collect();
类似地,在循环的
中,可以用
let mut v = vec![1, 2];
// Below is equivalent to: `for item in v.iter_mut() {`
for item in &mut v {
*item *= 2;
}
如果类型只有一种“方法”可以迭代,那么我们应该同时实现这两种方法。然而,如果有两种或两种以上的方法可以迭代,那么我们应该为每种方法提供一个特别的方法。
例如,
String
既不向iter提供,也不向iter提供
,因为迭代它有两种方法:以字节为单位迭代它的表示,或以字符为单位迭代它的表示。相反,它提供了两种方法:
方法的替代方法。字节
用于迭代字节,以及字符
用于迭代字符,作为iter
*好吧,从技术上讲,我们可以通过创建一个trait来做到这一点。但是我们需要为我们要使用的每种类型
impl
那个trait。同时,std
中的许多类型已经实现了IntoIterator
。
我(一个铁锈新手)从谷歌来到这里,寻求一个其他答案无法提供的简单答案。下面是一个简单的答案:
iter()
通过引用迭代项目 into\u iter()
迭代项目,将其移动到新范围因此,对于my\u vec{…}中的x本质上等同于my\u vec。into\u iter()。对于每个(| x |…)-两者都将my\u vec的元素移动到
范围。
如果您只需要查看数据,请使用
iter
,如果您需要编辑/修改它,请使用iter_mut
,如果您需要为其赋予新所有者,请使用into_iter
。
这很有帮助:http://hermanradtke.com/2015/06/22/effectively-using-iterators-in-rust.html
把它变成一个社区wiki,这样如果我犯了任何错误,希望Rust专业人士可以编辑这个答案。
TL;DR(灾难恢复):
into_iter
返回的迭代器可能会产生任何T
,
第一个问题是:“iter中的内容是什么?”
into_iter
来自IntoIterator
trait:
pub trait IntoIterator
where
<Self::IntoIter as Iterator>::Item == Self::Item,
{
type Item;
type IntoIter: Iterator;
fn into_iter(self) -> Self::IntoIter;
}
当您想要指定如何将特定类型转换为迭代器时,就可以实现这个特性。最值得注意的是,如果一个类型实现了迭代器,那么它可以在for循环中使用。
例如,Vec实现了迭代器。。。三次!
impl<T> IntoIterator for Vec<T>
impl<'a, T> IntoIterator for &'a Vec<T>
impl<'a, T> IntoIterator for &'a mut Vec<T>
每个变体略有不同。
这个函数消耗Vec,其迭代器直接生成值(
T):
impl<T> IntoIterator for Vec<T> {
type Item = T;
type IntoIter = IntoIter<T>;
fn into_iter(mut self) -> IntoIter<T> { /* ... */ }
}
另外两个通过引用获取向量(不要被
的签名愚弄到iter(self)
中,因为在这两种情况下self
都是引用),它们的迭代器将生成对Vec
中元素的引用。
这一个产生不可变的引用:
impl<'a, T> IntoIterator for &'a Vec<T> {
type Item = &'a T;
type IntoIter = slice::Iter<'a, T>;
fn into_iter(self) -> slice::Iter<'a, T> { /* ... */ }
}
虽然这会产生可变的引用:
impl<'a, T> IntoIterator for &'a mut Vec<T> {
type Item = &'a mut T;
type IntoIter = slice::IterMut<'a, T>;
fn into_iter(self) -> slice::IterMut<'a, T> { /* ... */ }
}
所以:
iter和iter之间有什么区别?
into\u iter是一种获取迭代器的通用方法,无论该迭代器生成值、不可变引用还是可变引用都取决于上下文,有时可能会令人惊讶。
iter和iter-mut是特殊方法。因此,它们的返回类型独立于上下文,通常是迭代器,分别生成不可变引用和可变引用。
Rust by example帖子的作者说明了对调用
into_iter
的上下文(即类型)的依赖所带来的惊讶,并且还通过使用以下事实来加剧问题:
Iterator(迭代器)不为
[T;N]
实现,仅为这对于into_iter
来说非常令人惊讶,因为所有类型(除了[T; N]
)都为所有3个变体(值和引用)实现了它。
数组在迭代器中实现了(以一种令人惊讶的方式),从而可以在循环中对它们的引用进行迭代。
从Rust 1.51开始,数组可以实现一个生成值的迭代器(通过数组::IntoIter),但现有的自动引用的IntoIterator实现使得很难通过IntoIterator通过值迭代实现。
问题内容: 因此,我正在观看RaymondHettinger的演讲“将代码转换为漂亮的惯用Python”,他提出了我从未意识到的这种形式。他的示例如下: 代替: 采用: 在查看的文档后,我发现了一个类似的示例: 这对我来说似乎很有用,但是我想知道您是否Pythonistas知道这种结构中不涉及I / O读取循环的任何示例吗?也许在标准库中? 我可以想到一些非常人为的示例,如下所示: 但这显然没有内
问题内容: 我想调试Java程序的整个流程。Eclipse中(进入)和(进入)之间有什么区别? 问题答案: 考虑以下代码,将当前指令指针(将在下一步执行的行,由表示)放在in 的行,并由in 的行调用: 如果此时要 进入 ,则将移至中的行,进入函数调用。 如果要在那一步 结束 ,您将移至中的行,从而结束函数调用。 调试器的另一个有用功能是单步 退出 或单步 返回。 在这种情况下,单步返回基本上将使
问题内容: 两者都意味着空间,但是有什么区别吗? 问题答案: 一个是不间断空间,另一个是常规空间。不间断的空格表示该行不应在该点处换行,就像它不会在一个单词的中间换行一样。 此外,正如斯文德(Svend)在其评论中指出的那样,不间断的空间不会崩溃。
本文向大家介绍<%# %> 和 <% %> 有什么区别?相关面试题,主要包含被问及<%# %> 和 <% %> 有什么区别?时的应答技巧和注意事项,需要的朋友参考一下 答:<%# %>表示绑定的数据源 <%%>是服务器端代码块
问题内容: 以下代码之间有什么区别: 和 Python建议采用一种做事方式,但有时似乎不止一种。 问题答案: 一个是函数调用,一个是文字: 使用第二种形式。它更具Python风格,并且可能更快(因为它不涉及加载和调用单独的函数)。
发展至今(2020 年 6 月份),GCC 编译器已经更新至 10.1.0 版本,其功能也由最初仅能编译 C 语言,扩增至可以编译多种编程语言,其中就包括 C++ 。 除此之外,当下的 GCC 编译器还支持编译 Go、Objective-C,Objective-C ++,Fortran,Ada,D 和 BRIG(HSAIL)等程序,甚至于 GCC 6 以及之前的版本还支持编译 Java 程序。但本