Несоответствие типа с использованием trim_end_matches в качестве функции закрытия: ожидаемая подпись … найдена подпись «для …»

#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 vs char::is_ascii_punctuation , и первое выполняется, self в то время как второе выполняется amp;self . Что касается конкретно, почему все методы ascii для char take amp;self , а не self , я понятия не имею. Тем более, что все методы, похоже, разыменовывают self в теле функции.