rdzawe łańcuchy(1): z węża do wielbłąda
Hej! Będzie to seria wpisów (a w zasadzie już jest to seria wpisów, bo już to zacząłem pisać). W każdym razie będę tu omawiał różne ciekawostki jeśli chodzi o stringi w Ruście. Np. dzisiaj omówimy sobie, w jaki sposób można napisać funkcję, która konwertuje takiego stringa
"foo_bar_baz"
na takiego:
"fooBarBaz"
Czyli zamieniamy z notacji snake case na camel case. Taka zabawa. A więc zaczynamy.
napiszemy sobie funkcję main oraz sygnaturę naszej funkcji:
fn main() {
println!("{}", to_camel_case("foo_bar_baz_qwerty"));
}
fn to_camel_case(s: &str) -> String {
}
Jak widać jest to funkcja, która pobiera wycinek stringa (string slice) i zwraca stringa o typie String (chodzi o to, że potrzebujemy stworzyć nowego stringa i go zaalokować na starcie, dlatego zwracamy String, a nie &str).
Dalej, stworzymy również wspomnianego już Stringa i go zwrócimy (na razie jest pusty). Możemy to zrobić poprzez `return out;`. Ale powiedzmy, że jesteśmy leniwi i nie chce nam się pisać średnika na końcu. Jeśli tak zrobimy, to i return nie będziemy musieli pisać, bo w Rust return jest domyślny na końcu funkcji jak nie dasz średnika. Więc zostanie samo `out`:
fn to_camel_case(s: &str) -> String {
let mut out = String::new();
out
}
Zauważ, deklarujemy go z modyfikatorem `mut`, ponieważ będziemy go mutować poprzez dodawanie do niego kolejnych stringów
Potrzebujemy jakoś oddzielić wyrazy przedzielone znakiem podkreślenia, do tego posłuży nam metoda split:
s.split("_")
wykorzystamy ją w pętli:
for word in s.split("_") {
out += &word[..1].to_uppercase();
out += &word[1..];
}
&word[..1] zwraca nam wycinek stringa zawierający pierwszą literę, zamieniamy go na uppercase i dodajemy do stringa `out`
&word[1..] zwraca nam wycinek stringa zawierający wszystko poza pierwszą literą i to dodajemy niezmienione.
Jaki jest tego efekt?
Wywołanie to_camel_case("foo_bar_baz_qwerty")
zwraca "FooBarBazQwerty"
No dobra, ale co jeśli chcemy, żeby pierwsza litera była mała (fooBarBazQwerty)?
Możemy sprawdzić w pętli, czy jest to pierwsza iteracja i jeśli tak, to dodać słowo w niezmienionej formie. Żeby to osiągnąć, trochę zmienimy naszą pętlę.
Zamiast for word in s.split("_")
napiszemy for (i, word) in s.split("_").enumerate()
, żeby mieć dostęp do zmiennej oznaczającej numer iteracji. Tradycyjnie nazywamy tę zmienną `i`
W samym ciele pętli natomiast dodajemy warunek sprawdzający, czy jest to pierwsza(tj. zerowa) iteracja i jeśli tak, to dodajemy słowo niezmienione:
if i == 0 {
out += word;
} else {
out += &word[..1].to_uppercase();
out += &word[1..];
}
Całość programu będzie wyglądać tak:
fn main() {
println!("{}", to_camel_case("foo_bar_baz_qwerty"));
}
fn to_camel_case(s: &str) -> String {
let mut out = String::new();
for (i, word) in s.split("_").enumerate() {
if i == 0 {
out += word;
} else {
out += &word[..1].to_uppercase();
out += &word[1..];
}
}
out
}
A jak odpalimy to przez carego run, to nam się wyświetli:
fooBarBazQwerty
I tu jest dobrze, jednak jak dodamy nieco inny string wejściowy, taki kończący się znakiem podkreślenia:
println!("{}", to_camel_case("foo_bar_"));
To program panikuje! Problem jest w tym, że wtedy word na końcu będzie pustym stringiem, więc tego typu wyrażenie &word[..1]
spowoduje panikę, bo próbujemy się dostać do elementu 1, jak nie ma takiego itemu. Dlatego możemy dodać dodatkowy warunek i sprawdzać, czy string nie jest pusty:
} else if word.len() > 0 {
Tak więc cały program po poprawkach wyglądać będzie tak:
fn main() {
println!("{}", to_camel_case("foo_bar_baz_qwerty"));
println!("{}", to_camel_case("foo_bar_"));
println!("{}", to_camel_case("_foo_bar"));
}
fn to_camel_case(s: &str) -> String {
let mut out = String::new();
for (i, word) in s.split("_").enumerate() {
if i == 0 {
out += word;
} else if word.len() > 0 {
out += &word[..1].to_uppercase();
out += &word[1..];
}
}
out
}
⭐️ W zasadzie tu jest jeszcze jedna poprawka do zrobienia, ale to już zostawiam tobie. Mianowicie jak dasz podkreślnik na początku:
println!("{}", to_camel_case("_foo_bar"));
To wyświetli FooBar (zamiast fooBar). Chodzi o to, że wtedy pusty string będzie pierwszym słowem, a foo będzie drugim, więc będzie uppercase'owane. No ale jak powiedziałem - to już wyzwanie dla ciebie. Zadanie z gwiazdką.
No, to był mój pierwszy tutorial do Rusta, jaki zrobiłem. Jak ci się podobało? Bo mi ciekawie się to pisało i chcę więcej takich pisać. Więc oczekuj kolejnych podobnych wpisów.
Ludzie na youtube w komentarzach piszą że Rust to żart, jest ogromny, jego składnia jest trudna w odczycie V, Hylo, Vale, Haxe, Hare, Odin, Roc są jeszcze lepsze niż Rust i Zig. Moim zdaniem Rust nie przyjmie się na rynku, powstanie coś lepszego od niego z podobnym zarządzaniem pamięcią ale prostsze i czytelniejsze. Jak Gleam.
OdpowiedzUsuńRust ma w kompilatorze pewne bonusy dlatego jest atak na C++.
OdpowiedzUsuń