
Size: a a a
fn equal_ignoring_case(a: &str, b: &str) -> bool {Правильное ли это решение? НЕТ, НЕПРАВИЛЬНОЕ, КТО ВООБЩЕ ТАК ПИШЕТ Технически оно верное, но оно делает много лишней работы. Что тут происходит? Сначала под первую строку выделяется место в куче, которое заполняется проходом по строке с преобразованиями по довольно нетривиальным правилам, во время которых выполняется бинарный поиск по захардкоженным таблицам, затем то же самое происходит для второй строки, и только после этого строки сравниваются друг с другом. Всё это происходит даже в том случае, если строки большие и даже если строки различаются уже первым символом.
a.to_lowercase() == b.to_lowercase()
}
fn equal_ignoring_case(a: &str, b: &str) -> bool {(тут используется почему-то малоизвестный метод Iterator::eq, который проверяет, что два итератора выдают равные последовательности элементов)
a.chars().flat_map(char::to_lowercase).eq(b.chars().flat_map(char::to_lowercase))
}
fn starts_with_ignoring_case(s: &str, prefix: &str) -> bool {, но оно не оптимально по тем же причинам. К сожалению, трюк с
s.to_lowercase().starts_with(&prefix.to_lowercase())
}
Iterator::eq
здесь не подойдёт, потому что этот метод может вернуть true
в том случае, если s
короче prefix
и потому не может его содержать. По аналогичным причинам не подойдёт Iterator::zip
. К сожалению, придется написать немного кода самому, с ручными вызовами next
:fn starts_with_ignoring_case(s: &str, prefix: &str) -> bool {
let mut s = s.chars().flat_map(char::to_lowercase);
let mut prefix = prefix.chars().flat_map(char::to_lowercase);
while let Some(s_ch) = s.next() {
match prefix.next() {
Some(p_ch) => if s_ch != p_ch {
return false
},
None => return true, //префикс закончился, а все символы до это совпадали
//значит, строка содержит префикс
}
}
//закончились символы в строке, и они все совпали с символами в префиксе
true
}
Разумеется, и тут применима оптимизация, если одна из строк состоит только из ASCII-символов:fn starts_with_ignoring_ascii_case(s: &str, prefix: &str) -> bool {
s.get(..prefix.len()).map_or(false, |start| start.eq_ignore_ascii_case(prefix))
}
Почему я решил об этом написать? Да потому что меня бесит, когда я вижу подобный настолько неоптимальный код. Так что можете считать, что это #бомбёжкипост.fn equal_ignoring_case(a: &str, b: &str) -> bool {Правильное ли это решение? НЕТ, НЕПРАВИЛЬНОЕ, КТО ВООБЩЕ ТАК ПИШЕТ Технически оно верное, но оно делает много лишней работы. Что тут происходит? Сначала под первую строку выделяется место в куче, которое заполняется проходом по строке с преобразованиями по довольно нетривиальным правилам, во время которых выполняется бинарный поиск по захардкоженным таблицам, затем то же самое происходит для второй строки, и только после этого строки сравниваются друг с другом. Всё это происходит даже в том случае, если строки большие и даже если строки различаются уже первым символом.
a.to_lowercase() == b.to_lowercase()
}
fn equal_ignoring_case(a: &str, b: &str) -> bool {(тут используется почему-то малоизвестный метод Iterator::eq, который проверяет, что два итератора выдают равные последовательности элементов)
a.chars().flat_map(char::to_lowercase).eq(b.chars().flat_map(char::to_lowercase))
}
fn starts_with_ignoring_case(s: &str, prefix: &str) -> bool {, но оно не оптимально по тем же причинам. К сожалению, трюк с
s.to_lowercase().starts_with(&prefix.to_lowercase())
}
Iterator::eq
здесь не подойдёт, потому что этот метод может вернуть true
в том случае, если s
короче prefix
и потому не может его содержать. По аналогичным причинам не подойдёт Iterator::zip
. К сожалению, придется написать немного кода самому, с ручными вызовами next
:fn starts_with_ignoring_case(s: &str, prefix: &str) -> bool {
let mut s = s.chars().flat_map(char::to_lowercase);
let mut prefix = prefix.chars().flat_map(char::to_lowercase);
while let Some(s_ch) = s.next() {
match prefix.next() {
Some(p_ch) => if s_ch != p_ch {
return false
},
None => return true, //префикс закончился, а все символы до это совпадали
//значит, строка содержит префикс
}
}
//закончились символы в строке, и они все совпали с символами в префиксе
true
}
Разумеется, и тут применима оптимизация, если одна из строк состоит только из ASCII-символов:fn starts_with_ignoring_ascii_case(s: &str, prefix: &str) -> bool {
s.get(..prefix.len()).map_or(false, |start| start.eq_ignore_ascii_case(prefix))
}
Почему я решил об этом написать? Да потому что меня бесит, когда я вижу подобный настолько неоптимальный код. Так что можете считать, что это #бомбёжкипост.starts_with_ignoring_case
с более простой реализацией.use postfix_macros::{postfix_macros, unwrap_or};
fn main() {
postfix_macros! {
let urls = ["https://rust-lang.org", "http://github.com"];
for url in urls.iter() {
let mut url_splitter = url.splitn(2, ':');
let scheme = url_splitter.next().unwrap();
let _remainder = url_splitter.next().unwrap_or! {
println!("Ignoring URL: No scheme found");
continue;
};
println!("scheme is {}", scheme);
}
}
}