不可变值仍在移动
immutable value is still being moved
我无法编译这个函数:
/// 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()
}
当前错误是:
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
我认为错误的来源是 chars
是一个迭代器,所以它发生变异,导致无法在闭包中借用,但即使我尝试声明一个局部变量(例如 let count = chars.count()
), 我仍然遇到借用错误。
我试过用 &
取消引用它,但也没用。
根据 cc
是 UTF8 还是 ASCII,您可以使用两种略有不同的方法来实现此功能。 UTF8 实现当然适用于这两种情况,因为 UTF8 是 ASCII 的超集。
fn maskify_utf8(cc: &str) -> String {
let last_four = cc.chars().count().saturating_sub(4);
cc.chars()
.enumerate()
.map(|(i, c)| if i < last_four { '#' } else { c })
.collect()
}
fn maskify_ascii(cc: &str) -> String {
let mask_idx = cc.len().saturating_sub(4);
format!("{0:#<1$}{2}", "#", mask_idx, &cc[mask_idx..])
}
fn main() {
assert_eq!(maskify_utf8("1234"), "####1234");
assert_eq!(maskify_utf8("abcd1234"), "####1234");
assert_eq!(maskify_ascii("abcd1234"), "####1234");
}
这里问题的症结在于Char::count()
消耗了self
。即使您声明了局部变量,在将所有权移至 count
函数后也不能使用 chars
:
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*
}
您可以通过创建新迭代器并使用它来获取 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");
}
或者你可以用 .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");
}
请注意 str.len()
可以 仅 处理 ascii 而 .chars().count()
可以处理完整的 utf8。
感谢@ibraheem-ahmed,我最终得到了这个解决方案:
/// Return a String with all characters masked as '#' except the last 4.
fn maskify(cc: &str) -> String {
let leading = cc.chars().count().saturating_sub(4);
cc
.chars()
.enumerate()
.map(|(i, c)| {
if i >= leading { c } else { '#' }
})
.collect()
}
我无法编译这个函数:
/// 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()
}
当前错误是:
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
我认为错误的来源是 chars
是一个迭代器,所以它发生变异,导致无法在闭包中借用,但即使我尝试声明一个局部变量(例如 let count = chars.count()
), 我仍然遇到借用错误。
我试过用 &
取消引用它,但也没用。
根据 cc
是 UTF8 还是 ASCII,您可以使用两种略有不同的方法来实现此功能。 UTF8 实现当然适用于这两种情况,因为 UTF8 是 ASCII 的超集。
fn maskify_utf8(cc: &str) -> String {
let last_four = cc.chars().count().saturating_sub(4);
cc.chars()
.enumerate()
.map(|(i, c)| if i < last_four { '#' } else { c })
.collect()
}
fn maskify_ascii(cc: &str) -> String {
let mask_idx = cc.len().saturating_sub(4);
format!("{0:#<1$}{2}", "#", mask_idx, &cc[mask_idx..])
}
fn main() {
assert_eq!(maskify_utf8("1234"), "####1234");
assert_eq!(maskify_utf8("abcd1234"), "####1234");
assert_eq!(maskify_ascii("abcd1234"), "####1234");
}
这里问题的症结在于Char::count()
消耗了self
。即使您声明了局部变量,在将所有权移至 count
函数后也不能使用 chars
:
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*
}
您可以通过创建新迭代器并使用它来获取 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");
}
或者你可以用 .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");
}
请注意 str.len()
可以 仅 处理 ascii 而 .chars().count()
可以处理完整的 utf8。
感谢@ibraheem-ahmed,我最终得到了这个解决方案:
/// Return a String with all characters masked as '#' except the last 4.
fn maskify(cc: &str) -> String {
let leading = cc.chars().count().saturating_sub(4);
cc
.chars()
.enumerate()
.map(|(i, c)| {
if i >= leading { c } else { '#' }
})
.collect()
}