이 코드 스 니펫이 있는 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는 무엇입니까?
답변
TL; DR :
- 반복자에 의해 반환 된
into_iter
임의의 수를 생성T
,&T
또는&mut T
상황에 따라. - 에 의해 반환 된 이터레이터는 규칙에 따라
iter
yield를 산출&T
합니다. - 에 의해 반환 된 이터레이터는 규칙에 따라
iter_mut
yield를 산출&mut T
합니다.
첫 번째 질문은 “무엇입니까 into_iter
?”
into_iter
IntoIterator
특성 에서 온다 :
pub trait IntoIterator where <Self::IntoIter as Iterator>::Item == Self::Item, { type Item; type IntoIter: Iterator; fn into_iter(self) -> Self::IntoIter; }
특정 유형을 반복자로 변환하는 방법을 지정하려는 경우이 특성을 구현합니다. 특히 유형이 구현 IntoIterator
하면 for
루프 에서 사용할 수 있습니다 .
예를 들어 … 3을 Vec
구현합니다 IntoIterator
!
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> { /* ... */ } }
다른 두 개는 벡터를 참조로 사용하고 ( 두 경우 모두 참조 into_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
그리고into_iter
?
into_iter
이 이터레이터가 값을 산출하는지, 불변의 참조 또는 변경 가능한 참조 가 컨텍스트에 의존 하고 때로는 놀랍지 않은지 반복자를 얻는 일반적인 방법 입니다.
iter
및 iter_mut
임시 방법입니다. 따라서 반환 유형은 컨텍스트와 무관하며 일반적으로 각각 불변 참조 및 변경 가능한 참조를 생성하는 반복자입니다.
Rust by Example 게시물의 저자 into_iter
는 호출 되는 컨텍스트 (예 : 유형)에 대한 의존성에서 오는 놀라움을 설명하고 다음 과 같은 사실을 사용하여 문제를 복잡하게 만듭니다.
IntoIterator
[T; N]
에 대해서만 구현되지 않으며&[T; N]
및&mut [T; N]
- 메소드가 값에 대해 구현되지 않으면 대신 해당 값에 대한 참조 를 자동으로 검색 합니다.
into_iter
모든 유형 (제외 [T; N]
)이 3 가지 변형 (값 및 참조)에 대해 구현 하기 때문에 매우 놀랍습니다 . 배열이 항목을 포기하기 위해 “축소”할 수 없기 때문에 값을 생성하는 반복자를 구현할 수 없습니다.
왜 배열이 IntoIterator
(놀라운 방식으로) 구현되는지에 관해서 는 for
루프 에서 배열 에 대한 참조를 반복 할 수 있습니다.
답변
나는 (Rust 초보자) 다른 답변으로는 제공되지 않은 간단한 답변을 찾기 위해 Google에서 왔습니다. 그 간단한 대답은 다음과 같습니다.
iter()
참조로 항목을 반복into_iter()
항목을 반복하여 새 범위로 이동iter_mut()
항목을 반복하여 각 항목에 대한 변경 가능한 참조를 제공합니다.
그래서 for x in my_vec { ... }
본질적으로 동일하다 my_vec.into_iter().for_each(|x| ... )
모두 – move
의 요소 my_vec
로 ...
범위.
데이터를 “보아야” iter
할 필요가있는 경우을 사용하고 , 데이터 를 편집 / 변경해야하는 경우을 사용하고을 사용 iter_mut
하고 새 소유자에게 제공해야하는 경우을 사용하십시오 into_iter
.
도움이되었습니다 : http://hermanradtke.com/2015/06/22/effectively-using-iterators-in-rust.html
내가 실수 한 경우 Rust 전문가 가이 답변을 편집 할 수 있도록 이것을 커뮤니티 위키로 만듭니다.
답변
.into_iter()
배열 자체에 대해서는 구현되지 않고 만 구현됩니다 &[]
. 비교:
impl<'a, T> IntoIterator for &'a [T]
type Item = &'a T
와
impl<T> IntoIterator for Vec<T>
type Item = T
이후 IntoIterator
에서만 정의 &[T]
, 슬라이스 자체와 같은 방법으로 제거 될 수 없습니다 Vec
당신이 값을 사용할 때를. (값은 이동할 수 없습니다)
자, 왜 그런 경우가 다른 문제인지, 저는 스스로 배우고 싶습니다. 추측 : 배열은 데이터 자체이며 슬라이스는보기 일뿐입니다. 실제로 배열을 다른 함수로 값으로 옮길 수 없으며 뷰를 전달하기 만하면 거기서도 소비 할 수 없습니다.
답변
좀 더 명확히 할 것이 있다고 생각합니다. 컬렉션과 같은 종류의, Vec<T>
그리고 VecDeque<T>
,이 into_iter
수익률이 있다는 방법 T
들이 구현 때문에를 IntoIterator<Item=T>
. Foo<T>
반복되는 유형을 작성하는 것을 막을 수있는 것은 없습니다 . T
다른 유형이 아닙니다 U
. 즉,를 Foo<T>
구현 IntoIterator<Item=U>
합니다.
사실, 몇 가지 예제가 있습니다 std
: &Path
구현 IntoIterator<Item=&OsStr>
및 &UnixListener
구현합니다 IntoIterator<Item=Result<UnixStream>>
.
차이 into_iter
및iter
의 차이에 원래의 질문으로 돌아 가기 into_iter
와 iter
. 다른 사람들이 지적한 것과 마찬가지로 차이점은에 지정된 모든 유형을 생성 할 수 into_iter
있는 필수 방법입니다 . 일반적으로, 타입 구현하는 경우 그것은 또한 두 개의 임시 방법을이 규칙에 따라, : 그리고 어떤 수율 및 각각.IntoIterator
IntoIterator::Item
IntoIterator<Item=I>
iter
iter_mut
&I
&mut I
의미 into_iter
하는 것은 특성 바인딩을 사용하여 메소드 가있는 유형 (즉 반복 가능) 을받는 함수를 만들 수 있다는 것입니다.
fn process_iterable<I: IntoIterator>(iterable: I) {
for item in iterable {
// ...
}
}
그러나, 우리는 할 수없는 * 가지고 유형을 요구하는 바인딩 특성 사용 iter
방법 또는 iter_mut
그들은 단지 규칙이기 때문에, 방법. 또는 into_iter
보다 더 널리 사용할 수 있다고 말할 수 있습니다 .iter
iter_mut
대안 iter
및iter_mut
관찰해야 할 또 다른 흥미로운 점 iter
은 반복자를 얻는 유일한 방법은 아닙니다 &T
. 관례에 따르면, 메소드 SomeCollection<T>
가 std
있는 콜렉션 유형 iter
에도 불변의 참조 유형이 &SomeCollection<T>
구현 IntoIterator<Item=&T>
됩니다. 예를 들어 &Vec<T>
implements IntoIterator<Item=&T>
이므로 다음을 반복 할 수 있습니다 &Vec<T>
.
let v = vec![1, 2];
// Below is equivalent to: `for item in v.iter() {`
for item in &v {
println!("{}", item);
}
경우 v.iter()
에 해당합니다 &v
구현하는 두 점에서 IntoIterator<Item=&T>
, 왜 다음 녹 모두를 제공합니까? 인체 공학적입니다. for
루프 에서는 사용하기 &v
보다 약간 더 간결합니다 v.iter()
. 그러나 다른 경우에는 다음 v.iter()
보다 훨씬 명확합니다 (&v).into_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();
마찬가지로 for
루프에서 다음 v.iter_mut()
과 &mut v
같이 바꿀 수 있습니다 .
let mut v = vec![1, 2];
// Below is equivalent to: `for item in v.iter_mut() {`
for item in &mut v {
*item *= 2;
}
유형에 대한 제공 (구현) into_iter
및 iter
방법
유형에 반복 할 “way”가 하나만 있으면 두 가지를 모두 구현해야합니다. 그러나 두 가지 이상의 방법을 반복 할 수있는 경우 각 방법마다 임시 방법을 제공해야합니다.
예를 들어, String
도 제공 into_iter
이나 iter
문자의 표현 바이트 또는 반복의 표현을 반복 : 반복하는 두 가지 방법이 있기 때문에 그것. 대신, 메소드의 대안으로 bytes
바이트 chars
반복 및 문자 반복을 위한 두 가지 방법을 제공합니다 iter
.
* 기술적으로 특성을 만들어서 할 수 있습니다. 그러나 우리는 우리가 impl
사용하고자하는 각 유형마다 그 특성이 필요 합니다. 한편 많은 유형의 std
이미 구현되어 IntoIterator
있습니다.