I can't get this function to compile:
/// Return a String with all characters masked as '#' except the last 4.
fn maskify(cc: &str) -> String {
let chars = cc.to_string().chars();
chars
.enumerate()
.map(|(i, c)| {
if i > chars.count() - 4 { '#' } else { c }
})
.collect()
}
The current errors are:
error[E0507]: cannot move out of `chars`, a captured variable in an `FnMut` closure
--> src/lib.rs:7:21
|
3 | let chars = cc.to_string().chars();
| ----- captured outer variable
...
7 | if i > &chars.count() - 4 { '#' } else { c }
| ^^^^^ move occurs because `chars` has type `std::str::Chars<'_>`, which does not implement the `Copy` trait
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:3:17
|
3 | let chars = cc.to_string().chars();
| ^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
4 | chars
| ----- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
error[E0382]: use of moved value: `chars`
--> src/lib.rs:6:14
|
3 | let chars = cc.to_string().chars();
| ----- move occurs because `chars` has type `std::str::Chars<'_>`, which does not implement the `Copy` trait
4 | chars
| ----- value moved here
5 | .enumerate()
6 | .map(|(i, c)| {
| ^^^^^^^^ value used here after move
7 | if i > &chars.count() - 4 { '#' } else { c }
| ----- use occurs due to use in closure
I think the source of the error is that chars
is an iterator, so it mutates, making it impossible to borrow in the closure, but even if I try to declare a local variable (such as let count = chars.count()
), I still get borrow errors.
I've tried dereferencing it with &
, but that didn't work either.
The crux of the issue here is that Char::count()
consumes self
. Even if you declare a local variable, you cannot use chars
after you moved ownership to the count
function:
fn maskify(cc: &str) {
let chars = cc.to_string().chars();
// ^^^^^ move occurs here
let count = chars.count();
// ^^^^^^ `chars` moved because `count` consumes self
let _ = chars.enumerate();
// ^^^^^ value used here after move - *this is not allowed*
}
You can fix this issue by creating a new iterator and consuming that to get the count
:
fn maskify(cc: &str) -> String {
let chars = cc.chars();
let count = cc.chars().count();
// ^^^ create and consume a new iterator over cc
chars
.enumerate()
.map(|(i, c)| {
if i < count - 4 { '#' } else { c }
})
.collect()
}
fn main() {
assert_eq!(maskify("abcd1234"), "####1234");
}
Or you can get the length of the string with .len()
:
fn maskify(cc: &str) -> String {
let chars = cc.chars();
chars
.enumerate()
.map(|(i, c)| {
if i < cc.len() - 4 { '#' } else { c }
})
.collect()
}
fn main() {
assert_eq!(maskify("abcd1234"), "####1234");
}
Note that str.len()
can only handle ascii while .chars().count()
can handle full utf8.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With