> For the complete documentation index, see [llms.txt](https://bagus-cahyono.gitbook.io/programming-notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bagus-cahyono.gitbook.io/programming-notes/rust/rustlings_exercise/09_strings.md).

# Strings

* `String` can be mutated.
* `&str` borrowed, immutable string slice.
* References:
  * [Strings](https://doc.rust-lang.org/book/ch08-02-strings.html)

## strings1.rs

```rust
// TODO: Fix the compiler error without changing the function signature.
fn current_favorite_color() -> String {
    String::from("blue")
}

fn main() {
    let answer = current_favorite_color();
    println!("My current favorite color is {answer}");
}
```

* In this exercise the function is expecting `String` as return type but got `&str` instead.
* `"hello"` is `&str` and we just need to convert it into `String`.
* We can use either one of below expressions:

  ```rust
  String::from("blue")
  "blue".to_string()
  ```

## strings2.rs

```rust
// TODO: Fix the compiler error in the `main` function without changing this function.
fn is_a_color_word(attempt: &str) -> bool {
    attempt == "green" || attempt == "blue" || attempt == "red"
}

fn main() {
    let word = String::from("green"); // Don't change this line.

    if is_a_color_word(&word) {
        println!("That is a color word I know!");
    } else {
        println!("That is not a color word I know.");
    }
}
```

* Similar problem with previous exercise.
* The function is expecting `&str` but got `String` instead.
* So we can convert it using either codes below:

  ```rust
  is_a_color_word(&word)
  is_a_color_word(word.as_str())
  ```

## strings3.rs

```rust
fn trim_me(input: &str) -> &str {
    // TODO: Remove whitespace from both ends of a string.
    input.trim()
}

fn compose_me(input: &str) -> String {
    // TODO: Add " world!" to the string! There are multiple ways to do this.
    format!("{input} world!")
}

fn replace_me(input: &str) -> String {
    // TODO: Replace "cars" in the string with "balloons".
    input.replace("cars", "balloons")
}

fn main() {
    // You can optionally experiment here.
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn trim_a_string() {
        assert_eq!(trim_me("Hello!     "), "Hello!");
        assert_eq!(trim_me("  What's up!"), "What's up!");
        assert_eq!(trim_me("   Hola!  "), "Hola!");
    }

    #[test]
    fn compose_a_string() {
        assert_eq!(compose_me("Hello"), "Hello world!");
        assert_eq!(compose_me("Goodbye"), "Goodbye world!");
    }

    #[test]
    fn replace_a_string() {
        assert_eq!(
            replace_me("I think cars are cool"),
            "I think balloons are cool",
        );
        assert_eq!(
            replace_me("I love to look at cars"),
            "I love to look at balloons",
        );
    }
}
```

* In this exercise we have 3 task.
* First is to trim given `&str` in function `trim_me` and return `&str`.
  * We can use `trim` method to do this.
* Second is to add `" world!"` into given `&str` in function `compose_me`.
  * We have multiple option to do this.
  * But because `&str` is immutable we cannot just simply use `+`.
  * We can either convert it into `String` first or use `format` macro like below.

    ```rust
    format!("{input} world!")
    input.to_string() + " world!"
    ```
* Last is to replace occurrence of `cars` to `balloons` in function `replace_me`.
  * We can do this by using `replace` method.

## strings4.rs

```rust
// Calls of this function should be replaced with calls of `string_slice` or `string`.
fn placeholder() {}

fn string_slice(arg: &str) {
    println!("{arg}");
}

fn string(arg: String) {
    println!("{arg}");
}

// TODO: Here are a bunch of values - some are `String`, some are `&str`.
// Your task is to replace `placeholder(…)` with either `string_slice(…)`
// or `string(…)` depending on what you think each value is.
fn main() {
    string_slice("blue");

    string("red".to_string());

    string(String::from("hi"));

    string("rust is fun!".to_owned());

    string("nice weather".into());

    string(format!("Interpolation {}", "Station"));

    // WARNING: This is byte indexing, not character indexing.
    // Character indexing can be done using `s.chars().nth(INDEX)`.
    string_slice(&String::from("abc")[0..1]);

    string_slice("  hello there ".trim());

    string("Happy Monday!".replace("Mon", "Tues"));

    string("mY sHiFt KeY iS sTiCkY".to_lowercase());
}
```

* In this exercise we need to replace `placeholder` with either `string` or `string_slice` for given parameters.
* I explain each of the line below:

  ```rust
  // "blue" is &str
  string_slice("blue");
  // to_string() return String
  string("red".to_string());
  // String
  string(String::from("hi"));
  // to_owned() return String
  string("rust is fun!".to_owned());
  // Here, both answers work.
  // `.into()` converts a type into an expected type.
  // If it is called where `String` is expected, it will convert `&str` to `String`.
  string("nice weather".into());
  // format return String
  string(format!("Interpolation {}", "Station"));
  // &str because it a slice
  string_slice(&String::from("abc")[0..1]);
  // trim return &str
  string_slice("  hello there ".trim());
  // replace return String
  string("Happy Monday!".replace("Mon", "Tues"));
  // to_lowercase() return String
  string("mY sHiFt KeY iS sTiCkY".to_lowercase());
  ```
* Basically anything that require string manipulation usually return `String` and if no string manipulation usually return `&str`
