У меня есть, казалось бы, простая проблема извлечения первого и последнего буквенно-цифрового символа из строки в Rust. Пожалуйста, рассмотрите мой минималистичный пример ниже:
fn main() {
let s: String = "Peace to the world!".to_string();
// check: string is not empty
if !s.is_empty() {
let s = s.to_uppercase();
let fidx = s.find(char::is_alphanumeric).unwrap();
println!("fidx: {fidx}");
let fchar = s.get(fidx..fidx).unwrap();
println!("fchar: {fchar}");
let lidx = s.rfind(char::is_alphanumeric).unwrap();
println!("lidx: {lidx}");
let lchar = s.get(lidx..lidx).unwrap();
println!("lchar: {lchar}");
}
}
Мой код возвращает пустые символы как для fchar, так и для lchar. Как мне получить эти символы из моей строки? Не могли бы вы также проверить мой код? Я не уверен, что это самое короткое и элегантное решение.
Обратите внимание, что fidx..fidx — это эксклюзивный диапазон, поэтому в настоящее время вы пытаетесь извлечь диапазоны, где c в fidx <= c < fidx, который всегда пуст. Пожалуйста, попробуйте с fidx..=fidx.
Все в порядке! С этой записью &s[fidx..=fidx] всё работает, но это очень громоздко. Есть ли лучшее, более элегантное решение?


fidx..fidx всегда пусто, поскольку второе значение является исключительным.
Вероятно, вы имели в виду использовать включающий диапазон:
let fchar = &s[fidx..=fidx];
Но технически это не дает вам первый символ, это дает вам &str первого символа и работает только в том случае, если его ширина в представлении UTF-8 составляет ровно 1 байт.
Поэтому вместо этого, если вам не нужен индекс, вы можете получить первый char, который соответствует критерию, с помощью этого:
let fchar = s.chars().find(|c| c.is_alphanumeric()).unwrap();
Или оба сразу с этим:
let (fidx, fchar) = s.char_indices().find(|(_, c)| c.is_alphanumeric()).unwrap();
Примечание. .char_indices() дает вам итератор по индексу байта и соответствующему символу, который вычисляет ваш код. Если вам нужен индекс символа, вы можете заменить его на .chars().enumerate()
В последнем случае просто замените find на rfind:
let lchar = s.chars().rfind(|c| c.is_alphanumeric()).unwrap();
let (lidx, lchar) = s.char_indices().rfind(|(_, c)| c.is_alphanumeric()).unwrap();
Можете ли вы объяснить детали закрытия? Что происходит в замыкающих телах?
Он вызывает char::is_alphanumeric(c)⁉ Не знаю, что тут объяснять, поскольку это простой вызов функции.
Зачем нам нужна ссылка |&c| в аргументах закрытия? Что означает это обозначение |&(_, c)|? Что мы отбрасываем индекс?
А, вы имеете в виду аргументы, &c — это шаблон ссылки, он разыменовывает переданный аргумент, что необходимо, потому что Iterator::find дает нам только ссылки на элементы. str::find может давать нам значения только потому, что знает тип и что char это Copy, поэтому он просто дает вам копию. Аналогично, &(_, c) — это шаблон, и да, для этого шаблона мы отбрасываем индекс, который является первым элементом кортежа (он нам все равно не нужен для проверки).
Для
&strи других фрагментов.get(x).unwrap()можно записать как[x]