404 #960
Replies: 12 comments 4 replies
-
|
哈喽有人吗 |
Beta Was this translation helpful? Give feedback.
-
|
咋404了 |
Beta Was this translation helpful? Give feedback.
-
|
哦可以 |
Beta Was this translation helpful? Give feedback.
-
|
|
Beta Was this translation helpful? Give feedback.
-
|
这是还没写吧 |
Beta Was this translation helpful? Give feedback.
-
|
写的非常精彩醍醐灌顶 |
Beta Was this translation helpful? Give feedback.
-
|
404 |
Beta Was this translation helpful? Give feedback.
-
|
路过 |
Beta Was this translation helpful? Give feedback.
-
|
依旧是404 |
Beta Was this translation helpful? Give feedback.
-
|
这里讲的真的精彩 滑稽.png |
Beta Was this translation helpful? Give feedback.
-
|
看来作者还没写, 贴一个前一阵子看迭代器源码的笔记, 给大家做参考 Iterator TricksIterator 是一个特征, 用来实现迭代器. 这些特征很多常用库都会用到, 并且特质基本相同, 因此直接整理该特征是很有必要的. 迭代器定义关联1个类型: Item, 代指迭代器内元素的类型 pub trait Iterator {
/// The type of the elements being iterated over.
type Item;迭代器方法注: 方法名带 &mut 类方法==可变迭代器==: 这类方法需要迭代器是可变的(
|
| 输出类型 | From | To |
|---|---|---|
Box |
IntoIterator<Item = I> | Box<[I]> |
BinaryHeap |
IntoIterator<Item = T> | BinaryHeap<T> |
BTreeMap |
IntoIterator<Item = (K, V)> | BTreeMap<K, V> |
BTreeSet |
IntoIterator<Item = T> | BTreeSet<T> |
LinkedList |
IntoIterator<Item = T> | LinkedList<T> |
VecDeque |
IntoIterator<Item = T> | VecDeque<T> |
Rc |
IntoIterator<Item = T> | Rc<[T]> |
String |
IntoIterator<Item = char> | String |
| IntoIterator<Item = &'a char> | String | |
| IntoIterator<Item = &'a str> | String | |
| IntoIterator<Item = String> | String | |
| IntoIterator<Item = Box<str>> | String | |
| IntoIterator<Item = Cow<'a, str>> | String | |
Cow |
IntoIterator<Item = char> | Cow<'a, str> |
| IntoIterator<Item = &'b str> | Cow<'a, str> | |
| IntoIterator<Item = String> | Cow<'a, str> | |
| IntoIterator<Item = T> | Cow<'a, [T] | |
Arc |
IntoIterator<Item = T> | Arc<[T]> |
Vec |
IntoIterator<Item = T> | Vec<T> |
Option |
IntoIterator<Item = Option<A>> | Option<V> |
Result |
IntoIterator<Item = Result<A, E>> | Result<V, E> |
unit |
IntoIterator<Item = ()> | () |
TokenStream |
IntoIterator<Item = TokenTree> | TokenStream |
| IntoIterator<Item = TokenStream> | TokenStream | |
HashMap |
IntoIterator<Item = (K, V)> | HashMap<K, V, S> |
HashSet |
IntoIterator<Item = T> | HashSet<T, S> |
OsString |
IntoIterator<Item = OsString> | OsString |
| IntoIterator<Item = &'a OsStr> | OsString | |
| IntoIterator<Item = Cow<'a, OsStr>> | OsString | |
PathBuf |
IntoIterator<Item = P> | PathBuf |
Wtf8Buf |
IntoIterator<Item = CodePoint> | Wtf8Buf |
根据上表, 我们可以明确判断, 我们的迭代器到底能收集为哪些类型. 同时也可以发现, 当输入的迭代器为IntoIterator<Item = T> 也就是任意类型的迭代器时, 其输出类型是多样的, 如Vec<T>, HashSet<T, S>, BinaryHeap<T>, VecDeque<T>等等. 因此, 对输出类型进行注释很必要.
示例:
let chars = ['g', 'd', 'k', 'k', 'n'];
let hello: String = chars.iter()
.map(|&x| x as u8)
.map(|x| (x + 1) as char)
.collect();
assert_eq!("hello", hello);用collect查看是否有Err产生:
fn main() {
let results = [Ok(1), Err("nope"), Ok(3), Err("bad")];
let result: Result<Vec<_>, &str> = results.iter().cloned().collect();
// gives us the first error
println!("{:?}", result);
// Err("nope")
let results = [Ok(1), Ok(3)];
let result: Result<Vec<_>, &str> = results.iter().cloned().collect();
// gives us the list of answers
println!("{:?}", result);
// Ok([1, 3])
}为啥有这样的输出呢? 这实际上和 Result的from_iter()方法实现有关:
fn from_iter<I: IntoIterator<Item = Result<A, E>>>(iter: I) -> Result<V, E> {
iter::try_process(iter.into_iter(), |i| i.collect())
}泛型V是一个可以实现了 FromIterator<A> 的类型, 意思是可以将元素为A的迭代器转换为V这种集合类型, try_process()方法表明了:
Takes each element in the Iterator: if it is an Err, no further elements are taken, and the Err is returned. Should no Err occur, a container with the values of each Result is returned.
因此, 如果没有任何Err产生, 则返回用Ok包裹的集合V (如上例的[1, 3]), 只要出现一个Err立刻结束迭代, 直接返回Err包裹的信息(如上例的“Nope”).
partition
Consumes an iterator, creating two collections from it.
The predicate passed to partition() can return true, or false. partition() returns a pair, all of the elements for which it returned true, and all of the elements for which it returned false.
See also [is_partitioned()] and [partition_in_place()].
拆分迭代器. 将原迭代器消耗, 返回两个新迭代器组成的二元组, 元组左边迭代器为谓词为
true的元素, 右边为谓词为false的元素.==传入参数== f: 一个谓词闭包/条件闭包
O(n)复杂度, 没实现二分
fn partition<B, F>(self, f: F) -> (B, B)
where
Self: Sized,
B: Default + Extend<Self::Item>,
F: FnMut(&Self::Item) -> bool,
{
#[inline]
fn extend<'a, T, B: Extend<T>>(
mut f: impl FnMut(&T) -> bool + 'a,
left: &'a mut B,
right: &'a mut B,
) -> impl FnMut((), T) + 'a {
move |(), x| {
if f(&x) {
left.extend_one(x);
} else {
right.extend_one(x);
}
}
}
let mut left: B = Default::default();
let mut right: B = Default::default();
self.fold((), extend(f, &mut left, &mut right));
(left, right)
}max()
Returns the maximum element of an iterator.
If several elements are equally maximum, the last element is returned. If the iterator is empty, [None] is returned.
Note that [f32]/[f64] doesn't implement [Ord] due to NaN being incomparable. You can work around this by using [Iterator::reduce]:
消耗整个迭代器, 返回迭代器中最大元素
如果迭代器所有元素值都相等, 返回最后一个元素, 如果迭代器为空, 返回None
浮点数由于存在
Nan这个不可比较的值, 所以不能用max方法. 寻找最大值. 这可以使用reduce方法解决这个问题
fn max(self) -> Option<Self::Item>
where
Self: Sized,
Self::Item: Ord,
{
self.max_by(Ord::cmp)
}示例:
下面是用reduce代替max的一个示例
fn main() {
assert_eq!(
[2.4, f32::NAN, 1.3]
.into_iter()
.reduce(f32::min)
.unwrap(),
1.3
);
}min()
Returns the minimum element of an iterator.
返回迭代器中元素最小的值, 和
max的要求一致
fn min(self) -> Option<Self::Item>
where
Self: Sized,
Self::Item: Ord,
{
self.min_by(Ord::cmp)
}max_by_key
Returns the element that gives the maximum value from the specified function.
根据给出的指定函数, 判断迭代器的最值
==传入参数== f: 一个闭包, 该闭包返回一个已经实现
Ord排序特征的类型和
max直接比较元素大小不同,max_by_key先是将元素利用给的闭包做一次映射map(f), 映射(返回一个二元组, 第一个元素是映射结果, 第二个元素是原值, 做返回值用), 然后再进行max的比较
fn max_by_key<B: Ord, F>(self, f: F) -> Option<Self::Item>
where
Self: Sized,
F: FnMut(&Self::Item) -> B,
{
#[inline]
fn key<T, B>(mut f: impl FnMut(&T) -> B) -> impl FnMut(T) -> (B, T) {
move |x| (f(&x), x)
}
#[inline]
fn compare<T, B: Ord>((x_p, _): &(B, T), (y_p, _): &(B, T)) -> Ordering {
x_p.cmp(y_p)
}
let (_, x) = self.map(key(f)).max_by(compare)?;
Some(x)
}max_by
Returns the element that gives the maximum value with respect to the specified comparison function.
用指定地比较函数, 比较迭代器各个元素的值.
这是
max和max_by_key的底层方法==传入参数== compare: 一个闭包, 传入两个变量的引用, 输出这两个变量的比较结果
Ordering当 f 为
|&x, &y| x.cmp(y)(或者直接写成方法名Ord::cmp) 时,max_by就等于max当 f 为
|&x, &y| |g(x).cmp(g(y)|(这里g是一个映射函数, 即max_by_key(g)方法的传参闭包g)时,max_by就等于max_by_key
max_by更适合自定义最值, 必如如果我要自定义一个二元组, 这样的值时最大的:
- 第一个元素取最大, 第二个元素取最小
那此时就需要用
max_by要更优雅. (max_by_key也可以实现, 但不够优雅)详细见示例
fn max_by<F>(self, compare: F) -> Option<Self::Item>
where
Self: Sized,
F: FnMut(&Self::Item, &Self::Item) -> Ordering,
{
#[inline]
fn fold<T>(mut compare: impl FnMut(&T, &T) -> Ordering) -> impl FnMut(T, T) -> T {
move |x, y| cmp::max_by(x, y, &mut compare)
}
self.reduce(fold(compare))
}源码解释: 从前两个元素开始,利用
compare()的比较结果对元素逐个比较, 返回较大的元素再与下一个元素比较(reduce的作用), 直到所有元素比较完成
示例:
取自定义最值:
- 第一个元素取最大, 第二个元素取最小
fn main() {
let sort = [(0, 1), (5, 1), (5, 3), (3, 5)];
// 利用max_by, 实现自定义排序
let max_val = sort.iter().max_by(|&x, &y| {
match x.0.cmp(&y.0) {
std::cmp::Ordering::Equal => y.1.cmp(&x.1),
other => other
}
}).unwrap();
println!("{:?}", max_val);
// 有些数据类型, 也可以使用sort_by_key实现相同功能
// 但和数据类型相关, 比如比较的是usize, 可能代码就又需要改变
let max_key_val = sort.iter().max_by_key(|&x| (x.0, -x.1)).unwrap();
assert_eq!(max_val, max_key_val);
}min_by_key
Returns the element that gives the minimum value from the specified function.
根据给定函数判断最值
fn min_by_key<B: Ord, F>(self, f: F) -> Option<Self::Item>
where
Self: Sized,
F: FnMut(&Self::Item) -> B,
{
#[inline]
fn key<T, B>(mut f: impl FnMut(&T) -> B) -> impl FnMut(T) -> (B, T) {
move |x| (f(&x), x)
}
#[inline]
fn compare<T, B: Ord>((x_p, _): &(B, T), (y_p, _): &(B, T)) -> Ordering {
x_p.cmp(y_p)
}
let (_, x) = self.map(key(f)).min_by(compare)?;
Some(x)
}min_by
Returns the element that gives the minimum value with respect to the specified comparison function.
自定义比较函数, 实现最小值比较. 比较函数是一个返回
Ordering枚举的函数详见
max_by
fn min_by<F>(self, compare: F) -> Option<Self::Item>
where
Self: Sized,
F: FnMut(&Self::Item, &Self::Item) -> Ordering,
{
#[inline]
fn fold<T>(mut compare: impl FnMut(&T, &T) -> Ordering) -> impl FnMut(T, T) -> T {
move |x, y| cmp::min_by(x, y, &mut compare)
}
self.reduce(fold(compare))
}rev()
Reverses an iterator's direction.
翻转迭代器输出顺序. 必须是双端迭代器
DoubleEndedIterator才可应用所有从左连接的方法均变成了右连接(从右索引)
fn rev(self) -> Rev<Self>
where
Self: Sized + DoubleEndedIterator,
{
Rev::new(self)
}uzip
Converts an iterator of pairs into a pair of containers.
将一个二元组迭代器转换为两个迭代器
如
[(1, 2), (3, 4), (5, 6)]–>[1, 3, 5]和[2, 4, 6]迭代器的元素必须是二元组
(A, B), 可以看出来,rust的zip打包解包方法没有python智能, python 的zip()可以输入很多迭代器, 组合成一个多元组, 同时zip(*)又可以把一个多元组/列表等等解包成原来的很多迭代器当然了, 为什么rust没实现呢? 因为不同迭代器的类型可能不同, 没有一种迭代器, 可以让两种不同类型的放到一起(如果有, 那可能是
box等类型, 但是它就失去了性能), 因此不同类型的迭代器很难实现用同一方法. 但我们可以根据这个方法, 对特定容器自己实现这个功能.
fn unzip<A, B, FromA, FromB>(self) -> (FromA, FromB)
where
FromA: Default + Extend<A>,
FromB: Default + Extend<B>,
Self: Sized + Iterator<Item = (A, B)>,
{
let mut unzipped: (FromA, FromB) = Default::default();
unzipped.extend(self);
unzipped
}copied()
Creates an iterator which copies all of its elements.
This is useful when you have an iterator over &T, but you need an iterator over T.
用于将引用变为值. 元素必须实现了
Copy特征底层是利用
Option的copied()方法: 通过模式匹配, 把Some(&T)变为Some(T)
fn copied<'a, T: 'a>(self) -> Copied<Self>
where
Self: Sized + Iterator<Item = &'a T>,
T: Copy,
{
Copied::new(self)
}cloned()
Creates an iterator which [clone]s all of its elements.
This is useful when you have an iterator over &T, but you need an iterator over T.
There is no guarantee whatsoever about the clone method actually being called or optimized away. So code should not depend on either.
消耗迭代器的所有元素, 克隆所有元素创建一个新迭代器
这个方法也可以把
&T变为T, 但元素可以没实现Copy特征无法保证
cloned是被调用执行了还是被底层优化掉了(未执行), 所以所编写的代码应该不要依赖它.
fn cloned<'a, T: 'a>(self) -> Cloned<Self>
where
Self: Sized + Iterator<Item = &'a T>,
T: Clone,
{
Cloned::new(self)
}示例:
cloned可能在底层被优化掉, 从而实现错误答案, 因此我们应避免cloned()这种写法直接生成迭代器, 可能会出问题.
// 下面这个代码是没有出问题的, 只是不好
fn main() {
let a = [1, 2, 3];
let v = a.iter().copied();
// 不要写这种依赖代码
let v_dont = v.clone();
// 最好写这种代码
let v_use = a.iter();
for i in v {
println!("{}", i)
}
for i in v_dont {
println!("{i}")
}
}cycle()
Repeats an iterator endlessly.
消耗原迭代器, 转换为周期的无限循环迭代器
原来的
None变成原迭代器的第一个item, 周而复始
这里还要说明一下, 这个迭代器的
next()也可能返回None, 如果原迭代器是空迭代器时, 就返回None
fn cycle(self) -> Cycle<Self>
where
Self: Sized + Clone,
{
Cycle::new(self)
}sum()
Sums the elements of an iterator.
An empty iterator returns the zero value of the type.
sum() can be used to sum any type implementing [Sum] [core::iter::Sum], including [Option] and [Result].
消耗迭代器, 对元素所有元素. 元素要实现了
Sum特征
fn sum<S>(self) -> S
where
Self: Sized,
S: Sum<Self::Item>,
{
Sum::sum(self)
}product()
Iterates over the entire iterator, multiplying all the elements
An empty iterator returns the one value of the type.
叠乘迭代器. 消耗迭代器, 返回所有元素相乘的结果
这个方法和
sum方法都可以用flod和reduce实现
fn product<P>(self) -> P
where
Self: Sized,
P: Product<Self::Item>,
{
Product::product(self)
}示例
// 计算n的阶乘
fn fa(n: i32) -> i32 {
(1..n).product()
}
// 也可以用reduce实现
fn fa2(n: i32) -> i32 {
(1..n).reduce(|a, b| a * b).unwrap_or(1)
}
fn fa2(n: i32) -> i32 {
(1..n).reduce(std::ops::Mul::mul).unwrap_or(1)
}cmp
Lexicographically compares the elements of this [Iterator] with those of another.
Lexicographical comparison
Lexicographical comparison is an operation with the following properties:
- Two sequences are compared element by element.
- The first mismatching element defines which sequence is lexicographically less or greater than the other.
- If one sequence is a prefix of another, the shorter sequence is lexicographically less than the other.
- If two sequences have equivalent elements and are of the same length, then the sequences are lexicographically equal.
- An empty sequence is lexicographically less than any non-empty sequence.
- Two empty sequences are lexicographically equal.
按字典序比较两个迭代器大小, 返回比较结果
Ordering
Less: 左边小于右边,Equal: 左边等于右边,Greater: 左边大于右边 A.fn(B) A为左边, B为右边
fn cmp<I>(self, other: I) -> Ordering
where
I: IntoIterator<Item = Self::Item>,
Self::Item: Ord,
Self: Sized,
{
self.cmp_by(other, |x, y| x.cmp(&y))
}partial_cmp
Lexicographically compares the [PartialOrd] elements of this [Iterator] with those of another. The comparison works like short-circuit evaluation, returning a result without comparing the remaining elements. As soon as an order can be determined, the evaluation stops and a result is returned.
partial, 部分的. 对部分有序的类型进行比较大小
按字典序比较两个迭代器大小, 返回比较结果
Option(Ordering)产生
Option的原因是, 类型Item可能存在不能比较大小的值, 因此当与不能比较大小的值比较是, 返回None
fn partial_cmp<I>(self, other: I) -> Option<Ordering>
where
I: IntoIterator,
Self::Item: PartialOrd<I::Item>,
Self: Sized,
{
self.partial_cmp_by(other, |x, y| x.partial_cmp(&y))
}cmp和partical_cmp的区别!
-
cmp 方法实现了
std::cmp::Ordtrait,它用于完全有序(total order)的类型。这意味着所有同类的值都可以相互比较,总是能确定一个值是小于、等于或大于另一个值。cmp方法返回一个std::cmp::Ordering枚举值,表示 Less、Equal 或 Greater。 -
partial_cmp 方法实现了
std::cmp::PartialOrdtrait,这个 trait 用于部分有序(partial order)或者说是可能无法比较的所有类型。部分有序意味着某些值可能无法直接比较(例如,NaN(Not a Number)在浮点数中就不与任何值相等,包括自己,也不比任何值大或小)。partial_cmp返回一个Option<Ordering>,当两个值可以比较时,它会返回Some(Ordering);如果值不能比较(这种情况在实现了PartialOrd但没有实现Ord的类型中可能出现),则返回None。
示例:
use std::cmp::Ordering;
assert_eq!([1.0, f64::NAN].iter().partial_cmp([2.0, f64::NAN].iter()), Some(Ordering::Less
assert_eq!([2.0, f64::NAN].iter().partial_cmp([1.0, f64::NAN].iter()), Some(Ordering::Grea
assert_eq!([f64::NAN, 1.0].iter().partial_cmp([f64::NAN, 2.0].iter()), None);eq
Determines if the elements of this [Iterator] are equal to those of another.
消耗迭代器, 判断两个迭代器是否相等
fn eq<I>(self, other: I) -> bool
where
I: IntoIterator,
Self::Item: PartialEq<I::Item>,
Self: Sized,
{
self.eq_by(other, |x, y| x == y)
}ne
Determines if the elements of this [Iterator] are not equal to those of another.
判断两个迭代器是否不等
fn ne<I>(self, other: I) -> bool
where
I: IntoIterator,
Self::Item: PartialEq<I::Item>,
Self: Sized,
{
!self.eq(other)
}lt
Determines if the elements of this [Iterator] are lexicographically comp less than those of another.
判断左边迭代器是否字典序小于右边迭代器
fn lt<I>(self, other: I) -> bool
where
I: IntoIterator,
Self::Item: PartialOrd<I::Item>,
Self: Sized,
{
self.partial_cmp(other) == Some(Ordering::Less)
}le
Determines if the elements of this [Iterator] are lexicographically less or equal to those of another.
判断迭代器是是否小于或等于其他迭代器
fn le<I>(self, other: I) -> bool
where
I: IntoIterator,
Self::Item: PartialOrd<I::Item>,
Self: Sized,
{
matches!(self.partial_cmp(other), Some(Ordering::Less | Ordering::Equal))
}gt
Determines if the elements of this [Iterator] are lexicographically greater than those of another.
greater. 左边是否大于右边迭代器
fn gt<I>(self, other: I) -> bool
where
I: IntoIterator,
Self::Item: PartialOrd<I::Item>,
Self: Sized,
{
self.partial_cmp(other) == Some(Ordering::Greater)
}ge
Determines if the elements of this [Iterator] are lexicographically greater than or equal to those of another.
greater or equal. 左边是否大于等于右边
fn ge<I>(self, other: I) -> bool
where
I: IntoIterator,
Self::Item: PartialOrd<I::Item>,
Self: Sized,
{
matches!(self.partial_cmp(other), Some(Ordering::Greater | Ordering::Equal))
}Beta Was this translation helpful? Give feedback.
-
|
404 |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
404
https://course.rs/pitfalls/stack-overflow.html
Beta Was this translation helpful? Give feedback.
All reactions