#rust #char #ascii #predicate
#Ржавчина #символ #ascii #предикат
Вопрос:
У меня есть приведенный ниже код для подсчета слов, в которых знаки препинания игнорируются.
use std::collections::HashMap;
fn word_count(words: amp;str) -> HashMap<String, u32> {
let mut hm: HashMap<String, u32> = HashMap::new();
words
.split_whitespace()
.map(|word| word.trim_end_matches(char::is_ascii_punctuation))
.map(|word| {
hm.entry(word.to_string())
.and_modify(|val| *val = 1)
.or_insert(0)
});
hm
}
Но компилятор жалуется с
error[E0631]: type mismatch in function arguments
--> src/lib.rs:7:26
|
7 | .map(|word| word.trim_end_matches(char::is_ascii_punctuation))
| ^^^^^^^^^^^^^^^^
| |
| expected signature of `fn(char) -> _`
| found signature of `for<'r> fn(amp;'r char) -> _`
|
= note: required because of the requirements on the impl of `std::str::pattern::Pattern<'_>` for `for<'r> fn(amp;'r char) -> bool {std::char::methods::<impl char>::is_ascii_punctuation}`
Я не могу понять, что на самом деле означает ошибка или чем мое использование отличается от того, что указано в документах для trim_end_matches
: assert_eq!("123foo1bar123".trim_end_matches(char::is_numeric), "123foo1bar");
Комментарии:
1. В дополнение к моему ответу, я бы рекомендовал изменить final
map
наfor
цикл. Помещать побочные эффекты вmap
функцию — не совсем хороший стиль, и это приводит к проблемам с заимствованием, которые здесь не нужны. Вот как я бы это исправил: play.rust-lang.org /…2. @PeterHall спасибо за предложение. Я просто попробовал этот подход после прочтения вашего ответа ниже. Еще раз спасибо.
Ответ №1:
Как указано в ошибке, trim_end_matches
ожидается, что аргументом будет функция, которая принимает char
, но char::is_ascii_punctuation
принимает свой аргумент по ссылке.
Вы можете просто добавить закрытие для преобразования:
.map(|word| word.trim_end_matches(|c| char::is_ascii_punctuation(amp;c)))
Большинство методов предиката на char
(например is_alphanumerc
) принимают self
, но по историческим причинам обратной совместимости (см. Комментарии RFC) принимают методы, специфичные для ASCII amp;self
. Для методов, отличных от ASCII, вы могли бы просто сделать, например:
.map(|word| word.trim_end_matches(char::is_alphanumeric))
Комментарии:
1. Я только что посмотрел на подпись для
char::is_numeric
vschar::is_ascii_punctuation
, и первое выполняется,self
в то время как второе выполняетсяamp;self
. Что касается конкретно, почему все методы ascii дляchar
takeamp;self
, а неself
, я понятия не имею. Тем более, что все методы, похоже, разыменовываютself
в теле функции.