10

I'm trying to trim and lowercase my String.

Currently I have

use dialoguer::Input;
    
let input: String = Input::new()
    .with_prompt("Guess a 5 letter word")
    .interact_text()
    .unwrap(); 
let guess: &str = input.as_str(); // trim and lowercase

I'm trying to transform String into a trimmed and lowercased &str but some functions are only on &str and others only on String so I'm having trouble coming up with an elegant solution.

TL;DR: End goal have guess be a trimmed and lowercase &str

1
  • String derefs to &str, so you can access str methods from String and if you want a &str as result, just do &input[..] Commented Feb 18, 2022 at 13:21

2 Answers 2

19

Rust stdlib is not about elegance, but about correctness and efficiency.

In your particular case, trim() is defined as str::trim(&self) -> &str because it always returns a substring of the original string, so it does not need to copy or allocate a new string, just compute the begin and end, and do the slice.

But to_lowercase() is defined as str::to_lowercase(&self) -> String because it changes each of its characters to the lowercase equivalent, so it must allocate and fill a new String.

You may thing that if you own the string you can mutate it to lowercase in-place. But that will not work in general because there is not a 1-to-1 map between lowercase and uppercase letters. Think of, for example ß <-> SS in German.

Naturally, you may know that your string only has ASCII characters... if so you can also use str::make_ascii_lowercase(&mut self) that does the change in-place, but only for ASCII characters that do have the 1-to-1 map.

So, summing up, the more ergonomic code would be, to trim input and copy to an owned lowercase:

let guess : String = input.trim().to_lowercase();

Or if you absolutely want to avoid allocating an extra string, but you are positive that only ASCII characters matter:

let mut input = input; //you could also add the mut above
input.make_ascii_lowercase();
let guess: &str = input.trim();
Sign up to request clarification or add additional context in comments.

Comments

1

Try this:

let s = "   aBcD ";
let s2 = s.trim().to_lowercase();
println!("[{s}], [{s2}]");

The above will work if s is &str (as in my example) or String and it will print:

[   aBcD ], [abcd]

So the last line in your code (if you insist on having guess as &str) should become:

let guess: &str = &input.trim().to_lowercase();

Otherwise if you write just:

let guess = input.trim().to_lowercase();

, guess will be of type String, as that's what to_lowercase() returns.

2 Comments

I think it is also important to point out that since a &str is more or less just a reference to a String you can implicitly get a &str from a String when calling functions, but not the other way around. Since most string manipulation functions return a String, these functions can be easily chained together.
@Locke Good point!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.