Note: this question contains deprecated pre-1.0 code! The answer is correct, though.
To convert a str to an int in Rust, I can do this:
let my_int = from_str::<int>(my_str);
The only way I know how to convert a String to an int is to get a slice of it and then use from_str on it like so:
let my_int = from_str::<int>(my_string.as_slice());
Is there a way to directly convert a String to an int?
You can directly convert to an int using the str::parse::<T>() method, which returns a Result containing the int.
let my_string = "27".to_string(); // `parse()` works with `&str` and `String`!
let my_int = my_string.parse::<i32>().unwrap();
You can either specify the type to parse to with the turbofish operator (::<>) as shown above or via explicit type annotation:
let my_int: i32 = my_string.parse().unwrap();
Since parse() returns a Result, it will either be an Err if the string couldn't be parsed as the type specified (for example, the string "peter" can't be parsed as i32), or an Ok with the value in it.
let my_u8: u8 = "42".parse().unwrap();
let my_u32: u32 = "42".parse().unwrap();
// or, to be safe, match the `Err`
match "foobar".parse::<i32>() {
Ok(n) => do_something_with(n),
Err(e) => weep_and_moan(),
}
str::parse::<u32> returns a Result<u32, core::num::ParseIntError> and Result::unwrap "Unwraps a result, yielding the content of an Ok [or] panics if the value is an Err, with a panic message provided by the Err's value."
str::parse is a generic function, hence the type in angle brackets.
If you get your string from stdin().read_line, you have to trim it first.
let my_num: i32 = my_num.trim().parse()
.expect("please give me correct string number!");
With a recent nightly, you can do this:
let my_int = from_str::<int>(&*my_string);
What's happening here is that String can now be dereferenced into a str. However, the function wants an &str, so we have to borrow again. For reference, I believe this particular pattern (&*) is called "cross-borrowing".
You can use the FromStr trait's from_str method, which is implemented for i32:
let my_num = i32::from_str("9").unwrap_or(0);
Yes, you can use the parse method on a String to directly convert it to an integer lik so:
let my_string = "42".to_string();
let my_int = my_string.parse::<i32>().unwrap();
The parse method returns a Result object, so you will need to handle the case where the string cannot be parsed into an integer. You can use unwrap as shown above to get the value if the parse was successful, or it will panic if the parse failed.
Or you can use the match expression to handle the success and failure cases separately like so:
let my_string = "42".to_string();
let my_int = match my_string.parse::<i32>() {
Ok(n) => n,
Err(_) => {
println!("Failed to parse integer");
0
},
};
FYI, the parse method is available for any type that implements the FromStr trait, which includes all of the integer types (e.g. i32, i64, etc.) as well as many other types such as f32 and bool.
Well, no. Why there should be? Just discard the string if you don't need it anymore.
&str is more useful than String when you need to only read a string, because it is only a view into the original piece of data, not its owner. You can pass it around more easily than String, and it is copyable, so it is not consumed by the invoked methods. In this regard it is more general: if you have a String, you can pass it to where an &str is expected, but if you have &str, you can only pass it to functions expecting String if you make a new allocation.
You can find more on the differences between these two and when to use them in the official strings guide.
So basically you want to convert a String into an Integer right!
here is what I mostly use and that is also mentioned in official documentation..
fn main() {
let char = "23";
let char : i32 = char.trim().parse().unwrap();
println!("{}", char + 1);
}
This works for both String and &str
Hope this will help too.
Related
How does one create a std::ffi::CString from a String in Rust?
Assume the String is already stored in a variable that can be moved if necessary, NOT a literal like it is in many of the examples for constructing a CString.
I have studied the docs for both CString:
https://doc.rust-lang.org/std/ffi/struct.CString.html
and String:
https://doc.rust-lang.org/std/string/struct.String.html
and I still don't see the path. You must have to go through one of the many pointer types; Into and From aren't implemented for these types, so .into() doesn't work.
String implements Into<Vec<u8>> already:
use std::ffi::CString;
fn main() {
let ss = "Hello world".to_string();
let s = CString::new(ss).unwrap();
println!("{:?}", s);
}
Playground
I'm a beginner to Rust and just learning the ownership concept.
I'm using this function to reverse a String
fn reverse(input: &str) -> String {
//we are receiving a borrowed value,
input
//get an iterator of chars from the string slice
.chars()
//Goes between two iterators.
//From the doc: double-ended iterator with the direction inverted.
.rev()
//collect into a String
.collect::<String>()
}
fn process_reverse_case(input: &str, expected: &str) {
assert_eq!(&reverse(input), expected)
}
fn main() {
process_reverse_case("robot", "tobor");
}
I would like to understand who owns robot and tobor.
I'm passing a borrowed value. Which is a string slice.
I understand this can't be modified. So when we are collecting the reversed string, I think we are collecting it into a argument 1 of assert_eq!. Am I right?
But as the process of reversing + collection happens inside reverse, the memory needed keeps increasing. Does argument 1 of assert_eq! account for that?
The above question might have been solved by the compiler at compile time. Am I right?
Your claims are mostly wrong, let me try to correct them.
Passing a string slice, returning a string slice
fn reverse(input: &str) -> String you are accepting a string slice, but returning a String. A String "has ownership over the contents of the string".
I understand this [a string slice] can't be modified
You can modify a &mut str, e.g.
fn to_lower(s: &mut str) {
s.make_ascii_lowercase();
}
fn main() {
let mut a = String::from("ABC");
println!("{}", a);
to_lower(&mut a);
println!("{}", a);
}
(playground)
So when we are collecting the reversed string, I think we are collecting it into a argument 1 of assert_eq!
No. You collect it into a string, that is what collect::<String>() is for. Also your function reverse returns a String.
This means, that you are calling the function reverse, which returns a String and you are passing that String as the first "argument" to the assert_eq! macro.
the memory needed keeps increasing. Does argument 1 of assert_eq! account for that?
No, how should it? That's all done inside of the reverse function. assert_eq! just takes two parameters. Where they come from is uncertain and not needed to know.
assert_eq!(&reverse(input), expected)
What happens in this line is, that you are calling your reverse function with input as parameter. But normally you can't compare &T with T (a reference to something with an actual instance of something), that's where the & (ampersand) in front of reverse comes into play. String implements the Deref trait which means it can be seen as a str as well (see the doc for Deref). But now you are trying to compare a str with &str, which does not work and that's why you put & in front, so you actually end up with &str and &str which you can compare with ==.
I would like to understand who ownes robot and tobor.
Nobody. In fact they live inside of the data section in the ELF/Binary itself. They don't have an owner per se, but can be used as &str wherever needed.
I am attempting to write a lexer for fun, however something keeps bothering me.
let mut chars: Vec<char> = Vec::new();
let mut contents = String::new();
let mut tokens: Vec<&String> = Vec::new();
let mut append = String::new();
//--snip--
for _char in chars {
append += &_char.to_string();
append = append.trim().to_string();
if append.contains("print") {
println!("print found at: \n{}", append);
append = "".to_string();
}
}
Any time I want to do something as simple as append a &str to a String I have to convert it using .to_string, String::from(), .to_owned, etc.
Is there something I am doing wrong, so that I don't have to constantly do this, or is this the primary way of appending?
If you're trying to do something with a type, check the documentation. From the documentation for String:
push: "Appends the given char to the end of this String."
push_str: "Appends a given string slice onto the end of this String."
It's important to understand the differences between String and &str, and why different methods accept and return each of them.
A &str or &mut str are usually preferred in function arguments and return types. That's because they are just pointers to data so nothing needs to be copied or moved when they are passed around.
A String is returned when a function needs to do some new allocation, while &str and &mut str are slices into an existing String. Even though &mut str is mutable, you can't mutate it in a way that increases its length because that would require additional allocation.
The trim function is able to return a &str slice because that doesn't involve mutating the original string - a trimmed string is just a substring, which a slice perfectly describes. But sometimes that isn't possible; for example, a function that pads a string with an extra character would have to return a String because it would be allocating new memory.
You can reduce the number of type conversions in your code by choosing different methods:
for c in chars {
append.push(c); // append += &_char.to_string();
append = append.trim().to_string();
if append.contains("print") {
println!("print found at: \n{}", append);
append.clear(); // append = "".to_string();
}
}
There isn't anything like a trim_in_place method for String, so the way you have done it is probably the only way.
In Python, this would be final_char = mystring[-1]. How can I do the same in Rust?
I have tried
mystring[mystring.len() - 1]
but I get the error the type 'str' cannot be indexed by 'usize'
That is how you get the last char (which may not be what you think of as a "character"):
mystring.chars().last().unwrap();
Use unwrap only if you are sure that there is at least one char in your string.
Warning: About the general case (do the same thing as mystring[-n] in Python): UTF-8 strings are not to be used through indexing, because indexing is not a O(1) operation (a string in Rust is not an array). Please read this for more information.
However, if you want to index from the end like in Python, you must do this in Rust:
mystring.chars().rev().nth(n - 1) // Python: mystring[-n]
and check if there is such a character.
If you miss the simplicity of Python syntax, you can write your own extension:
trait StrExt {
fn from_end(&self, n: usize) -> char;
}
impl<'a> StrExt for &'a str {
fn from_end(&self, n: usize) -> char {
self.chars().rev().nth(n).expect("Index out of range in 'from_end'")
}
}
fn main() {
println!("{}", "foobar".from_end(2)) // prints 'b'
}
One option is to use slices. Here's an example:
let len = my_str.len();
let final_str = &my_str[len-1..];
This returns a string slice from position len-1 through the end of the string. That is to say, the last byte of your string. If your string consists of only ASCII values, then you'll get the final character of your string.
The reason why this only works with ASCII values is because they only ever require one byte of storage. Anything else, and Rust is likely to panic at runtime. This is what happens when you try to slice out one byte from a 2-byte character.
For a more detailed explanation, please see the strings section of the Rust book.
As #Boiethios mentioned
let last_ch = mystring.chars().last().unwrap();
Or
let last_ch = codes.chars().rev().nth(0).unwrap();
I would rather have (how hard is that!?)
let last_ch = codes.chars(-1); // Not implemented as rustc 1.56.1
While I understand basically what str and std::string::String are and how they relate to each other, I find it a bit cumbersome to compose strings out of various parts without spending too much time and thought on it. So as usual I suspect I did not see the proper way to do it yet, which makes it intuitive and a breeze.
let mut s = std::string::String::with_capacity(200);
let precTimeToJSON = | pt : prectime::PrecTime, isLast : bool | {
s.push_str(
"{ \"sec\": "
+ &(pt.sec.to_string())
+ " \"usec\": "
+ &(pt.usec.to_string())
+ if isLast {"}"} else {"},"})
};
The code above is honored by the compiler with error messages like:
src\main.rs:25:20: 25:33 error: binary operation + cannot be applied to type &'static str [E0369]
And even after half an hours worth of fiddling and randomly adding &, I could not make this compilable. So, here my questions:
What do I have to write to achieve the obvious?
What is the "standard" way to do this in Rust?
The Rust compiler is right (of course): there's no + operator for string literals.
I believe the format!() macro is the idiomatic way to do what you're trying to do. It uses the std::fmt syntax, which essentially consists of a formatting string and the arguments to format (a la C's printf). For your example, it would look something like this:
let mut s: String = String::new();
let precTimeToJSON = | pt : prectime::PrecTime, isLast : bool | {
s = format!("{{ \"sec\": {} \"usec\": {} }}{}",
pt.sec,
pt.usec,
if isLast { "" } else { "," }
)
};
Because it's a macro, you can intermix types in the argument list freely, so long as the type implements the std::fmt::Display trait (which is true for all built-in types). Also, you must escape literal { and } as {{ and }}, respectively. Last, note that the format string must be a string literal, because the macro parses it and the expanded code looks nothing like the original format! expression.
Here's a playground link to the above example.
Two more points for you. First, if you're reading and writing JSON, have a look at a library such as serde. It's much less painful!
Second, if you just want to concatenate &'static str strings (that is, string literals), you can do that with zero run-time cost with the concat!() macro. It won't help you in your case above, but it might with other similar ones.
Itertools::format can help you write this as a single expression if you really want to.
let times: Vec<PrecTime>; // iterable of PrecTime
let s = format!("{}", times.iter().format(",", |pt, f|
f(&format_args!(r#"{{ "sec": {}, "usec": {} }}"#, pt.sec, pt.usec))
));
format() uses a separator, so just specify "," there (or "" if you need no separator). It's a bit involved so that the formatting can be completely lazy and composable. You receive a callback f that you call back with a &Display value (anything that can be Display formatted).
Here we demonstrate this great trick of using &format_args!() to construct a displayable value. This is something that comes in handy if you use the debug builder API as well.
Finally, use a raw string so that we don't need to escape the inner " in the format: r#"{{ "sec": {} "usec": {} }}"#. Raw strings are delimited by r#" and "# (free choice of number of #).
Itertools::format() uses no intermediate allocations, it is all directly passed on to the underlying formatter object.
You can also do this madness:
fn main() {
let mut s = std::string::String::with_capacity(200);
// Have to put this in a block so precTimeToJSON is dropped, see https://doc.rust-lang.org/book/closures.html
{
// I have no idea why this has to be mut...
let mut precTimeToJSON = |sec: u64, usec: u64, isLast: bool| {
s.push_str(&( // Coerce String to str. See https://doc.rust-lang.org/book/deref-coercions.html
"{ \"sec\": ".to_string() // String
+ &sec.to_string() // + &str (& coerces a String to a &str).
+ " \"usec\": " // + &str
+ &usec.to_string() // + &str
+ if isLast {"}"} else {"},"} // + &str
));
};
precTimeToJSON(30, 20, false);
}
println!("{}", &s);
}
Basically the operator String + &str -> String is defined, so you can do String + &str + &str + &str + &str. That gives you a String which you have to coerce back to a &str using &. I think this way is probably quite inefficient though as it will (possibly) allocate loads of Strings.