1

I have

use std::io;

fn main() {
    println!("CHAR COUNT");
    let mut guess = String::new();
    io::stdin().read_line(&mut guess).expect(
        "Failed to read line",
    );

    let string_length = guess.len() - 2;
    let correct_string_length = guess.truncate(string_length);

    println!("Your text: {}", guess);
    println!("Your texts wrong length is: {}", string_length);
    println!("Your texts correct length: {}", correct_string_length);
}

The last line gives me

error[E0277]: the trait bound `(): std::fmt::Display` is not satisfied
  --> src/main.rs:15:47
   |
15 |     println!("Your texts correct length: {}", correct_string_length);
   |                                               ^^^^^^^^^^^^^^^^^^^^^ `()` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
   |
   = help: the trait `std::fmt::Display` is not implemented for `()`
   = note: required by `std::fmt::Display::fmt`

What am I doing wrong? If I use {:?} then I get () instead of a formatted string.

2
  • You should read the documentation a bit more closely :) Commented Aug 23, 2017 at 14:16
  • Possible duplicate of How do I sort an array? Commented Aug 23, 2017 at 14:27

3 Answers 3

9

When in doubt, go to the docs - here's the function signature of String::truncate:

fn truncate(&mut self, new_len: usize)

Note two things:

  • It takes self as &mut.
  • It has no return value.

From that, the problem becomes pretty clear - truncate does not return a new truncated string, it truncates the existing string in place.

This might seem a little unintuitive at first, but Rust APIs tend not to allocate new objects in memory unless you specifically ask them to - if you're never going to use guess again, then it'd be ineffecient to create a whole new String. If you wanted to make a truncated copy, then you'd need to be explicit:

let truncated = guess.clone();
truncated.truncate(string_length);

Or if you just wanted to reference part of the existing string, you could do what Ryan's answer suggests.

Sign up to request clarification or add additional context in comments.

Comments

5

Just to compliment the other answers here..

Attempting to truncate a string in Rust that is not on a character boundary will cause a runtime panic.

So while this works now:

let correct_string_length = &guess[..string_length];

If you're trying to truncate a string with wider characters, your code will panic at runtime. This is especially true if you're truncating user input.. who knows what it could be. For example:

fn main() {
    let s = "Hello, 世界";

    println!("{}", &s[..8]); // <--- panic
}

You can use the str::is_char_boundary(usize) method to make sure you're not about to break up a wide character accidentally:

fn print_safely(s: &str, mut idx: usize) {
    loop {
        if s.is_char_boundary(idx) || idx >= s.len() - 1 {
            break;
        }
        idx += 1;
    }

    println!("{}", &s[..idx]);
}

User input could be anything so this is just something to consider.

Playground link: http://play.integer32.com/?gist=632ff6c81c56f9ba52e0837ff25939bc&version=stable

Comments

4

truncate operates in place, which is why it returns (). Looks like you’re just looking for a regular non-mutating substring:

let correct_string_length = &guess[..string_length];

Comments

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.