Adding or reducing int to usize

I am trying to learn Rust and looking to do some string manipulation, but now looks like I need to go back to Go..

fn main() {
    let mut greeting = String::from("hello");
    greeting.insert_str(greeting.len() + 1,"World");
    println!("{}", greeting);
}

error message makes no sense to me, can someone please help making some sense to me.

thread 'main' panicked at 'assertion failed: self.is_char_boundary(idx)',

You’ll need to remove the + 1. Also appending at the end is easier with push_str. In case you’re also trying to get a space between “hello” and “World”, you’ll need to add the space, too.

Your string greeting is having its last byte at position greeting.len() - 1. Recall that things are indexed starting from 0. So greeting.len() already indicates a position after the string, in fact the first and the only accepted (by insert_str) index after the string’s contents.

If you read the docs of insert_str, you’ll find out more about panic conditions:

Panics

Panics if idx is larger than the String ’s length, or if it does not lie on a char boundary.

4 Likes

yeh! in fact I can do like this " world" , a space between them.
I am just trying understand how can we deal with such situations is there something like.

greeting.len() as i32

Or

(i32)greeting.len() + 1

how can we do type casting ? in the above situation.

Alright… type casting is possible, the syntactically simplest form would use the as operator, so greetings.len() as i32, as you already wrote. I don’t understand why you’re talking about type casting in the context of your code example above, because – to me – it doesn’t feel like you need to do any casting there.

Maybe you can elaborate on your thought process as to why and where you’d like to do coercion/casting?

2 Likes

If you want a space, you need to add a space character.

fn main() {
    let mut greeting = String::from("hello");
    greeting.push(' ');
    greeting.push_str("world");
    println!("{}", greeting);
}
2 Likes

Ok, I got it, thanks @steffahn and @cole-miller for your reply, I am impressed with the community support, this place rocks :v:

this reason for error was not casting related but as @cole-miller me, mentioned its due to length.
Casting is working for me, I think this is just initial hiccups.

fn main() {
    let  greeting = String::from("hello");
    println!("{}", greeting.len() as i32 + 1);
}

I see. Note that thread 'main' panicked at … is a runtime panic, which has to be distinguished from a compile-time error. Casting – or conversion in general – tend to not result in runtime error. Rust uses Result<T, E> for these kind of failures. Well… or in the case of as, you’re only getting compile-time errors or it works (however, as can truncate the value when converting from larger to smaller integer types). Panics can happen when you’re working with Result in case you’ve manually added a .unwrap() call, but in this case, it should be clear what the cause is.

Also, assertion failed: self.is_char_boundary(idx) hints at – which you might want to familiarize youself with a little bit – the UTF-8 encoding of strings in Rust. This is important: chars in Rust are unicode scalar values, and Strings or strs encode a sequence of these in UTF-8 which is a variable-length encoding. (ASCII chars take 1 byte, other chars up to 4 bytes). When interacting with strings, most/all indices you’re using e.g. for ranges/slicing – or e.g. like in your example for the index of insert_str – is byte-based, which means that the index might point into the middle of the encoding of a single char. This is obviously not a legal index to split the string at, and is_char_boundary is a method to test whether a byte-index falls onto the boundary between two chars.

So now that you know that, you’ll be able to understand that an error like

thread 'main' panicked at 'assertion failed: self.is_char_boundary(idx)',

Has nothing to do with type conversions, and has everything to do with passing an invalid index to a method of String or str. :wink:

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.