Solving parse() error in Rust for beginners - rust

this is my code. It takes a number and then panicks.
Code:
//Convert temperatures between Fahrenheit and Celsius.
use std::io;
fn main() {
let c: bool = true;
let f: bool = false;
let mut temperatur = String::new();
println!("Gib die Temperatur an:");
io::stdin()
.read_line(&mut temperatur)
.expect("Konnte nicht gelesen werden");
let temperatur_int: i32 = temperatur.parse::<i32>().unwrap();
println!("{}", temperatur_int);
}
Error:
Gib die Temperatur an: 5 thread 'main' panicked at 'called Result::unwrap()on anErrvalue: ParseIntError { kind: InvalidDigit }', src/main.rs:17:57 note: run withRUST_BACKTRACE=1 environment variable to display a backtrace
Tried to parse String to Integer

You're doing the right thing, but you forgot that you will get a newline in your string when reading from stdin. So instead of '32' you will have '32\n', which cannot be parsed.
So do trim() additionally before the parsing:
let temperatur_int: i32 = temperatur.trim().parse::<i32>().unwrap();

Related

I keep getting the following error thread 'main' panicked at 'Jjaanokapasao: ParseIntError { kind: InvalidDigit }', fahrenheit_celsius.rs:17:49

I'm very newbie when it comes related to Rust, and I keep getting this error and honestly, I have no clue what's going on. I'm doing a Fahrenheit to Celsius, and the other way around.
Here is my code:
use std::io;
fn main() {
let mut choose = String::new();
println!("Choose between Celsius To Fahrenheit [1] or Fahrenheit to Celsius [2],\
please introduce a corrected value (integer)");
io::stdin()
.read_line(&mut choose)
.expect("Failed to read!");
// Careful with the trim, cuz it's removing all characters and it causes and error that basically, closes the CMD
// Carriage return BE CAREFUL MAN!
if choose.trim() == "1" {
println!("Please, Introduce a value ");
io::stdin().read_line(&mut choose).expect("Please, enter an integer");
let choose: i32 = choose.trim().parse().expect("Jjaanokapasao");
ctof(choose);
} else if choose.trim() == "2" {
println!("Please, Introduce a value");
io::stdin().read_line(&mut choose).expect("Please, enter an integer");
let choose: usize = choose.trim_end().parse().expect("Failed to convert to i32");
ftpc(choose);
}
}
fn ctof(c: i32) {
let celsius_to_fahrenheit: i32 = (c * (9 / 5)) + 32;
println!("Here is your conversion: {celsius_to_fahrenheit}")
}
fn ftpc(f: usize) {
let fahrenheit_to_celsius: usize = (f-32) * (5 / 9);
println!("Here is your conversion: {fahrenheit_to_celsius}")
}
'''
Using .read_line() to read into a String will append to the existing data, not overwrite it. And you used .trim() it ignore the newline in your comparisons, but it still exists; it wasn't removed from the string. So if you enter 1 and then 26, the variable choose will contain "1\n26\n". Using .trim() will not remove the newline character in the middle so .parse() will encounter an invalid digit.
You should call choose.clear() before writing into it again or else use a different variable.

Rust: Is there a way to convert BufReader<File> to a String?

I'm working on a .obj reader in Rust, and I've run into a bit of an issue. The only way I've found you are able to read a file is through "BufReader", though I can't seem to be able to convert that to a String for further processing. Here's my code so far:
let input: BufReader<File> = BufReader::new(File::open("cube.obj").expect("didn't work"));
let model: Obj = Obj::load(input);
let s: String = input.chars()
.map(|x| x.ok().unwrap())
.take_while(|&x| x != ' ')
.collect();
println!("input: {}", input);
If anybody more experienced with rust knows what I could do, it would be very helpful. Thanks!
You have to import the trait std::io::Read and then can call Read::read_to_string to read the content of the file.
use std::fs::File;
use std::io::{BufReader, Read};
fn main() {
let mut input: BufReader<File> = BufReader::new(File::open("cube.obj").expect("didn't work"));
let mut str = String::new();
input.read_to_string(&mut str).expect("cannot read string");
println!("input: {}", str);
}

Why is my program panicking although the datatype is same?

Why is my program generating
thread 'main' panicked at 'called Result::unwrap() on an Err
value: ParseIntError { kind: InvalidDigit }', src/main.rs:68:54 note:
run with RUST_BACKTRACE=1 environment variable to display a
backtrace
when I enter the generated hash it panics instead of passing control to if {..}.
fn main() {
println!("Hello user! Please cast your input ");
let userinput: u64 = user_input();
let mut hasher_two = DefaultHasher::new();
let vecdata = [0x09, 0x06, 0xba, 0x67, 0x76];
hasher_two.write(&vecdata);
let final_check = hasher_two.finish();
if final_check == userinput {
correct_file_creation();
} else {
wrong_file_creation();
}
}
pub fn user_input() -> u64 {
let mut userinput = String::new();
std::io::stdin().read_line(&mut userinput).unwrap();
let userinputinteger: i32 = userinput.trim().parse().unwrap();
return userinputinteger as u64;
}
You need to be more specific, since you're not parsing a normal number.
You'll need to tell rust that you want to parse a hex string.
See this answer on how to do that:
Converting a hexadecimal string to a decimal integer
I do not know anything about rust but your error message suggests that because the error is in ParseIntError with a second clue in that error message: kind: InvalidDigit which means that it has no idea what an a or f is doing in your string that's supposed to be an integer.

How to read a text File in Rust and read mutliple Values per line

So basically, I have a text file with the following syntax:
String int
String int
String int
I have an idea how to read the Values if there is only one entry per line, but if there are multiple, I do not know how to do it.
In Java, I would do something simple with while and Scanner but in Rust I have no clue.
I am fairly new to Rust so please help me.
Thanks for your help in advance
Solution
Here is my modified Solution of #netwave 's code:
use std::fs;
use std::io::{BufRead, BufReader, Error};
fn main() -> Result<(), Error> {
let buff_reader = BufReader::new(fs::File::open(file)?);
for line in buff_reader.lines() {
let parsed = sscanf::scanf!(line?, "{} {}", String, i32);
println!("{:?}\n", parsed);
}
Ok(())
}
You can use the BuffRead trait, which has a read_line method. Also you can use lines.
For doing so the easiest option would be to wrap the File instance with a BuffReader:
use std::fs;
use std::io::{BufRead, BufReader};
...
let buff_reader = BufReader::new(fs::File::open(path)?);
loop {
let mut buff = String::new();
buff_reader.read_line(&mut buff)?;
println!("{}", buff);
}
Playground
Once you have each line you can easily use sscanf crate to parse the line to the types you need:
let parsed = sscanf::scanf!(buff, "{} {}", String, i32);
Based on: https://doc.rust-lang.org/rust-by-example/std_misc/file/read_lines.html
For data.txt to contain:
str1 100
str2 200
str3 300
use std::fs::File;
use std::io::{self, BufRead};
use std::path::Path;
fn main() {
// File hosts must exist in current path before this produces output
if let Ok(lines) = read_lines("./data.txt") {
// Consumes the iterator, returns an (Optional) String
for line in lines {
if let Ok(data) = line {
let values: Vec<&str> = data.split(' ').collect();
match values.len() {
2 => {
let strdata = values[0].parse::<String>();
let intdata = values[1].parse::<i32>();
println!("Got: {:?} {:?}", strdata, intdata);
},
_ => panic!("Invalid input line {}", data),
};
}
}
}
}
// The output is wrapped in a Result to allow matching on errors
// Returns an Iterator to the Reader of the lines of the file.
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where P: AsRef<Path>, {
let file = File::open(filename)?;
Ok(io::BufReader::new(file).lines())
}
Outputs:
Got: Ok("str1") Ok(100)
Got: Ok("str2") Ok(200)
Got: Ok("str3") Ok(300)

How to solve "value: ParseIntError" in rust?

I am trying to build a Fahrenheit to Celsius converter in Rust.
I compiled it successfully, but I don't know what went wrong in at runtime. Is this because of the conversion?
Here is my code:
use std::io;
fn main(){
println!("Please select\n 1.CELSIUS to FAHRENHEIT\n 2.FAHRENHEIT to CELSIUS");
const CEL_FAH: f64 = 32.00;
const FAH_CEL: f64 = -17.22;
let mut select = String::new();
io::stdin().read_line(&mut select)
.expect("Please select the appropriate options");
let select: i32 = select.parse().unwrap();
//control flow
if select == 1 {
println!("1. CELSIUS - FAHRENHEIT: ");
let cels = String::new();
let cels: f64 = cels.parse().unwrap();
let ans1 = cels * CEL_FAH;
println!("Conversions: {}", ans1);
} else if select == 2 {
println!("2. FAHRENHEIT - CELSIUS: ");
let fahs = String::new();
let fahs: f64 = fahs.parse().unwrap();
let ans2 = fahs * FAH_CEL;
println! ("Conversions: {}", ans2);
}else {
println!("Select the options please.");
}
}
Here is my output and error:
Compiling converter v0.1.0 (D:\Program Files\Rust Projects\converter)
Finished dev [unoptimized + debuginfo] target(s) in 2.46s
Running `target\debug\converter.exe`
Please select
1.CELSIUS to FAHRENHEIT
2.FAHRENHEIT to CELSIUS
2
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ParseIntError { kind: InvalidDigit }', src\main.rs:19:23
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: process didn't exit successfully: `target\debug\converter.exe` (exit code: 101)```
In your code, there are three mistakes:
When you're taking input using stdin() method and want to parse it into another type you have to put .trim() because stdin() adds whitespaces with your input so you need to trim those unwanted whitespaces.
Each time you are taking input you have to use io::stdin() method along with the read_line method so that the compiler hold for the user input.
You have used the wrong formula for conversion.
I have made the corrections in your code and it is working fine now, here is the snippet:
use std::io;
fn main() {
println!("Please select\n 1.CELSIUS to FAHRENHEIT\n 2.FAHRENHEIT to CELSIUS");
const CEL_FAH: f64 = 32.00;
const FAH_CEL: f64 = 1.8; //changed
let mut select = String::new();
io::stdin()
.read_line(&mut select)
.expect("Please select the appropriate options");
let select: i32 = select.trim().parse().unwrap(); // .trim() method requires when taking input
//control flow
if select == 1 {
println!("1. CELSIUS - FAHRENHEIT: ");
let mut cels = String::new();
io::stdin()
.read_line(&mut cels)
.expect("Please input a temperature in degrees"); // when you're taking input from user you have to use stdin()
let cels: f64 = cels.trim().parse().unwrap();
let ans1 = (cels * FAH_CEL) + CEL_FAH; //this the correct formula to convert from celsius to fahrenheit
println!("Conversions: {}", ans1);
} else if select == 2 {
println!("2. FAHRENHEIT - CELSIUS: ");
let mut fahs = String::new();
io::stdin()
.read_line(&mut fahs)
.expect("Please input a temperature in degrees"); //when you're taking input from user you have to use stdin()
let fahs: f64 = fahs.trim().parse().unwrap();
let ans2 = (fahs - CEL_FAH) * 5. / 9.; //this the correct formula to convert from fahrenheit to celsius
println!("Conversions: {}", ans2);
} else {
println!("Select the options please.");
}
}
You can also refer to this repository. Temperature converter rust
Your read_line also yielded a newline (the enter you pressed when selecting something). You first have to remove that from the input, for example like this:
select.truncate(select.len()-1);
Also, you have to specify the target-type that the string must be parsed to:
let select = select.parse::<i32>().unwrap();
(the rest of your snippet seems unfinished, so not responding to errors down there)

Resources