Clippy lints / Performance
Clippy lint · Performance · checked with Clippy 0.1.99
clippy::drain_collect: draining all elements of a collection into a new collection of the same type
What it meansChecks for calls to .drain() that clear the collection, immediately followed by a call to .collect(). “Collection” in this context refers to any type with a drain method: Vec, VecDeque, BinaryHeap, HashSet,HashMap, String It is in the performance group and warns by default.
What you see
warning: draining all elements of a collection into a new collection of the same type --> main.rs:4:5 | 4 | v.drain(..).collect() | ^^^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `std::mem::take(v)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/stable/index.html#drain_collect = note: `#[warn(clippy::drain_collect)]` on by default
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?
Using mem::take is faster as it avoids the allocation. When using mem::take, the old collection is replaced with an empty one and ownership of the old collection is returned.
Code that could be written to run faster. Warns by default.
How to fix it
Clippy can fix this one for you: run cargo clippy --fix (add --allow-dirty if you have uncommitted changes). Review the diff before you commit.
Flagged
fn remove_all(v: &mut Vec<i32>) -> Vec<i32> {
v.drain(..).collect()
}
Write this instead
use std::mem;
fn remove_all(v: &mut Vec<i32>) -> Vec<i32> {
mem::take(v)
}
Turn it off, or on
Allow it where it does not fit your code, as narrowly as you can:
On one item
#[allow(clippy::drain_collect)]
fn my_function() { /* ... */ }Whole crate (Cargo.toml)
[lints.clippy]
drain_collect = "allow"One run
cargo clippy -- -A clippy::drain-collectThe [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 calls to .drain() that clear the collection, immediately followed by a call to .collect().
“Collection” in this context refers to any type with a
drainmethod:Vec,VecDeque,BinaryHeap,HashSet,HashMap,String
Why is this bad?
Using mem::take is faster as it avoids the allocation.
When using mem::take, the old collection is replaced with an empty one and ownership of
the old collection is returned.
Known issues
mem::take(&mut vec) is almost equivalent to vec.drain(..).collect(), except that
it also moves the capacity. The user might have explicitly written it this way
to keep the capacity on the original Vec.
Example
fn remove_all(v: &mut Vec<i32>) -> Vec<i32> {
v.drain(..).collect()
}
Use instead:
use std::mem;
fn remove_all(v: &mut Vec<i32>) -> Vec<i32> {
mem::take(v)
}
From the Clippy lint list (0.1.99), part of the Rust project, MIT or Apache-2.0. Official entry.
Related lints
- large_enum_variantlarge size difference between variants
- cmp_ownedChecks for conversions to owned values just for the sake of a comparison
- collapsible_str_replaceChecks for consecutive calls to str::replace (2 or more) that can be collapsed into a single call
- double_ended_iterator_lastcalled `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
- expect_fun_callChecks for calls to .expect(&format!(...)), .expect(foo(..)), etc., and suggests to use unwrap_or_else instead
- extend_with_drainuse of `extend` instead of `append` for adding the full range of a second vector
- format_in_format_argsDetects format! within the arguments of another macro that does formatting such as format! itself, write! or println!
All 847 Clippy lints · Rust compiler errors · Cargo.toml checker
Up next
Related lintclippy::large_enum_variantlarge size difference between variantsRead it next →Did this answer your question?