Clippy lints / Suspicious
Clippy lint · Suspicious · checked with Clippy 0.1.99
clippy::by_ref_peekable_peek: calling `.by_ref().peekable().peek()` will advance the underlying iterator and consume its first output
What it meansChecks for usages of Iterator::by_ref().peekable().peek(). It is in the suspicious group and warns by default.
What you see
warning: calling `.by_ref().peekable().peek()` will advance the underlying iterator and consume its first output --> main.rs:4:9 | 4 | let x = iter.by_ref().peekable().peek(); // 1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/stable/index.html#by_ref_peekable_peek = note: `#[warn(clippy::by_ref_peekable_peek)]` on by default help: to peek the first item without advancing the underlying iterator, use | 4 - let x = iter.by_ref().peekable().peek(); // 1 4 + let x = iter.clone().next().as_ref(); // 1 | help: to advance the underlying iterator, use | 4 - let x = iter.by_ref().peekable().peek(); // 1 4 + let x = iter.next().as_ref(); // 1 | help: to make the iterator peekable, use | 3 ~ let mut iter = [1, 2, 3].into_iter().peekable(); 4 ~ let x = iter.peek(); // 1 |
Real output of Clippy 0.1.99 (Rust 1.99) on the example below. Names and line numbers in yours will differ.
Does it matter?
While it might look like this will allow peeking on the first element of an iterator without consuming it and without consuming the iterator itself, it will in practice consume the first element. The implementation of Peekable::peek() produces the first element of the underlying iterator, and stores it internally so that it can be later produced. As a consequence, it advances the underlying iterator, whose .next() method will now produce its second element.
Code that is most likely wrong or useless. Warns by default.
How to fix it
Clippy does not fix this one automatically (its suggestion may change behaviour, so it only shows it). Change the code by hand:
Flagged
let mut iter = [1, 2, 3].into_iter();
let x = iter.by_ref().peekable().peek(); // 1
let y = iter.by_ref().peekable().peek(); // 2
Write this instead
let mut iter = [1, 2, 3].into_iter();
let x = iter.next().as_ref(); // 1
let y = iter.next().as_ref(); // 2
Turn it off, or on
Allow it where it does not fit your code, as narrowly as you can:
On one item
#[allow(clippy::by_ref_peekable_peek)]
fn my_function() { /* ... */ }Whole crate (Cargo.toml)
[lints.clippy]
by_ref_peekable_peek = "allow"One run
cargo clippy -- -A clippy::by-ref-peekable-peekThe [lints] table needs Rust 1.74 or newer. In a workspace, put it under [workspace.lints.clippy] and add [lints] workspace = true to each member.
Clippy's own documentation
What it does
Checks for usages of Iterator::by_ref().peekable().peek().
Why is this bad?
While it might look like this will allow peeking on the first element of an iterator without consuming it and without consuming the iterator itself, it will in practice consume the first element.
The implementation of Peekable::peek() produces the first element
of the underlying iterator, and stores it internally so that it can
be later produced. As a consequence, it advances the underlying
iterator, whose .next() method will now produce its second element.
Example
let mut iter = [1, 2, 3].into_iter();
let x = iter.by_ref().peekable().peek(); // 1
let y = iter.by_ref().peekable().peek(); // 2
If this does what you intended, use the following instead, which is shorter and clearer:
let mut iter = [1, 2, 3].into_iter();
let x = iter.next().as_ref(); // 1
let y = iter.next().as_ref(); // 2
From the Clippy lint list (0.1.99), part of the Rust project, MIT or Apache-2.0. Official entry.
Related lints
- await_holding_refcell_refChecks for calls to await while holding a RefCell, Ref, or RefMut
- blanket_clippy_restriction_lints`clippy::restriction` is not meant to be enabled as a group
- block_scrutineeWarns when a match, if let, or while let scrutinee is wrapped in a block. This lint only triggers on the 2021 edition and older
- cast_abs_to_unsignedcasting the result of `i32::abs()` to u32
- cast_enum_constructorcast of an enum tuple constructor to an integer
- cast_enum_truncationcasting `main::E::X` to `u8` will truncate the value
All 847 Clippy lints · Rust compiler errors · Cargo.toml checker
Up next
Related lintclippy::await_holding_refcell_refChecks for calls to await while holding a RefCell, Ref, or RefMutRead it next →Did this answer your question?