Skip to content

Commit

Permalink
add(collections): pigify exercise
Browse files Browse the repository at this point in the history
  • Loading branch information
inancgumus committed Jun 12, 2020
1 parent 68e57ea commit 2696d52
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 9 deletions.
6 changes: 6 additions & 0 deletions rpl/_11_collections/exercises/exercise_2_solution/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions rpl/_11_collections/exercises/exercise_2_solution/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "exercise_2_solution"
version = "0.1.0"
authors = ["Inanc Gumus <[email protected]>"]
edition = "2018"

[dependencies]
61 changes: 61 additions & 0 deletions rpl/_11_collections/exercises/exercise_2_solution/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Convert strings to pig latin (_Keep in mind the details about UTF-8 encoding!_).
fn main() {
println!("{:10} -> {}", "apple", pigify("apple"));
println!("{:10} -> {}", "first", pigify("first"));

// let's pigify for multiple words
let s = "first consonant of each word is moved to the end of the word";

// create a string with `s.len() * 2` capacity to prevent
// memory fragmentation while adding new substrings.
let mut ns = String::with_capacity(s.len() * 2);

// split s to words, pigify, and add each one to `ns`.
let mut words = s.split_whitespace();
while let Some(w) = words.next() {
ns.push_str(pigify(w).as_str());
ns.push(' ');
}
println!("\n{}\n{}", s, ns);
}

// let's first make it work for a single word.
//
// pigify returns an owned String because
// it doesn't have to retain ownership
// to the returned String.
fn pigify(w: &str) -> String {
// get an utf-8 character iterator
let mut chars = w.chars();

// get the first utf-8 char, and move the iterator to the next char.
let first: char = match chars.next() {
Some(c) => c, // if `w` isn't empty, `first` is `c`
None => return "".to_string(), // otherwise, return "" from pigify()
};
// we use match here because `next()` returns an Option.

// transform the word
match first {
// if the word starts with a vowel:
//
// "apple" becomes "apple-hay"
//
'a' | 'e' | 'i' | 'o' | 'u' => format!("{}-hay", w),
// otherwise:
//
// "first" becomes "irst-fay"
//
// -> chars points to the 2nd char and forward.
// because we moved it near the start of pigify().
//
// -> as_str() returns a &str (a string slice) for that portion.
//
_ => format!("{}-{}ay", chars.as_str(), first),
//
// requirement was handling utf-8 properly.
// so you shouldn't do something like this: &w[1..]
// -> why? the first character could be multiple-bytes.
//
}
}
41 changes: 32 additions & 9 deletions rpl/_11_collections/src/strings.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
// ===================================================================
// 🤯 OMG
// I had a hard time learning through all of these String types.
// When I try to do the collection exercises, I couldn't know what to do.
// So I tried to reread the documentation, and also a lot of posts, etc.
// I think I finally came to understand the necessary knowledge to go on.
// ===================================================================

// ===================================================================
// ☝️ Rust wants you to put more thought when working with Strings.
// So that you'll be saved from string/character bugs later on.
Expand All @@ -22,6 +30,7 @@
// -> A fix-sized UTF-8 encoded string slice that refers to a
// hardcoded location in memory.
// -> Underlying type: &'static str
// -> `'static` means the value is hardcoded into the binary.
//
// ⭐️ &str
//
Expand Down Expand Up @@ -52,7 +61,17 @@
//
// -> Dynamic string type: Growable, and shrinkable.
// -> Owned, mutable, UTF-8 encoded, and heap-allocated.
// -> You can pass it as &String to a function that accepts &str.
//
// -> Its source code looks like this:
//
// pub struct String {
// vec: Vec<u8>,
// }
//
// => You can pass it as &String to a function that accepts &str.
// WHY?
// https://doc.rust-lang.org/std/string/struct.String.html#deref
//
//
// let s = String::from("hey");
//
Expand All @@ -61,15 +80,17 @@
// }
//
// p(&s);
// ^
// |
// ________/
// \ Above, Rust automatically does this:
// &*s
// ^^
// ||
// |+--> Dereferences to str
// +--> Borrows it
//
// WHY?
// https://doc.rust-lang.org/std/string/struct.String.html#deref
//
// -> Its source code looks like this:
//
// pub struct String {
// vec: Vec<u8>,
// }
// So it becomes a &str that points to the contents of s.
//
// ⭐️ Other String Types
//
Expand Down Expand Up @@ -239,3 +260,5 @@ pub fn run() {
// https://doc.rust-lang.org/book/ch08-02-strings.html
// https://doc.rust-lang.org/std/primitive.str.html
// https://doc.rust-lang.org/std/string/struct.String.html
// https://doc.rust-lang.org/src/alloc/string.rs.html
// https://doc.rust-lang.org/src/core/str/mod.rs.html

0 comments on commit 2696d52

Please sign in to comment.