In Rust, is it possible to chain more functions after ok, unwrap or expect?
Given code:
stdin()
.read_line(&mut guess)
.ok()
.expect("Couldn't read line!");
If I want to trim the string, is there a syntax like this?
stdin()
.read_line(&mut guess)
.ok().trim()
.expect("Couldn't read line!");
I know using match I could do it https://stackoverflow.com/a/56264723/15504324
In this case the problem is that, you cannot, because the buffer is guess, readline would return the bytes read
Anyway:
You can use map to operate the value in case there is any Before unwraping/expecting:
Ok("Foo bar ")
.ok()
.map(str::trim)
.expect("Couldn't read line!");
After it you can use the type already, so just chain the call.
Ok("Foo bar ")
.unwrap()
.trim();
Related
I am studying Rust and upon working on the Guessing Game I found this odd behaviour:
use std::io;
fn main() {
println!("Welcome!");
let mut input = String::new();
print!("Please type something:"); // this line is not printed UNTIL the Enter key is pressed
io::stdin()
.read_line(&mut input)
.expect("Failed to read input!");
println!("Bye!");
}
The following happens:
Welcome! is printed
Please type something: is NOT printed
If you type some text and press Enter, you will see your text followed by Please type something:Bye!
How can I print a message to the standard output and have the input being printed on the same line?
For instance:
Please enter your name:
(user types Chuck Norris)
Please enter your name: Chuck Norris
From the docs for std::print:
Note that stdout is frequently line-buffered by default so it may be necessary to use io::stdout().flush() to ensure the output is emitted immediately.
So looks like you need to call io::stdout().flush().
I'm new in rust and stuck in the error below, and i could not find any clue on it. Anyone can point me out? I got no idea how to define the read_line in float.
.read_line(&mut fahrenheit)
| ^^^^^^^^^^^^^^^ expected struct String, found f64
fn main(){
println!("enter fahrenheit: ");
//io::stdin() .read_line(&mut index) .expect("Failed to read line");
let mut fahrenheit: f64 = 66.66;
io::stdin()
.read_line(&mut fahrenheit)
.expect("fail to read");
let tempConvert = fahrenheitToCelsius(fahrenheit);
println!("convert from {tempConvert}");
}
fn fahrenheitToCelsius(x: f64) -> f64{
let mut gt: f64;
gt = (x - 32.00) * 5.00 / 9.00;
gt
}
read_line will read a string from stdin, and it needs a buffer to put it in, which is supposed to be argument you pass it. If, then, you want to convert it, it's your job: it won't do that on its own. Thus the type error. To achieve what you want, simply create a buffer, then parse it.
let mut buffer = String::new();
io::stdin().read_line(&mut buffer).expect("Failed to read");
let fahrenheit = buffer.trim().parse::<f64>().expect("Failed to parse as `f64'");
Note that in your code, the generic argument of parse might be left implicit since your fahrenheitToCelsius function might be enough for the compiler to figure out the type to perform the conversion to.
I am studying Rust and upon working on the Guessing Game I found this odd behaviour:
use std::io;
fn main() {
println!("Welcome!");
let mut input = String::new();
print!("Please type something:"); // this line is not printed UNTIL the Enter key is pressed
io::stdin()
.read_line(&mut input)
.expect("Failed to read input!");
println!("Bye!");
}
The following happens:
Welcome! is printed
Please type something: is NOT printed
If you type some text and press Enter, you will see your text followed by Please type something:Bye!
How can I print a message to the standard output and have the input being printed on the same line?
For instance:
Please enter your name:
(user types Chuck Norris)
Please enter your name: Chuck Norris
From the docs for std::print:
Note that stdout is frequently line-buffered by default so it may be necessary to use io::stdout().flush() to ensure the output is emitted immediately.
So looks like you need to call io::stdout().flush().
Consider this code to read the user input in rust
use std::io;
fn main() {
let mut input = String::new();
io::stdin()
.read_line(&mut input)
.expect("error: unable to read user input");
println!("{}", input);
}
why is there no way to do it like this?
use std::io;
fn main() {
let mut input = io::stdin()
.read_line()
.expect("error: unable to read user input");
println!("{}", input);
}
it would be more convenient to other languages
TL;DR The closest you have is lines(), and the reason read_line works like it does is efficiency. The version that uses lines() looks like this:
use std::io::{self, BufRead};
fn main() {
// get next line from stdin and print it
let input = io::stdin().lock().lines().next().unwrap().expect("IO error");
println!("{}", input);
}
In general, read_line() is not designed for use in small interactive programs; there are better ways to implement those.
The read_line method comes from the generic io::BufRead trait, and its primary use is reading input, typically redirected from files or other programs, and possibly coming in large quantities. When processing large amounts of data, it is advantageous to minimize the number of allocations performed, which is why read_line is designed to reuse an existing string. A typical pattern would be:
let mut line = String::new();
while input.read_line(&mut line)? != 0 {
// do something with line
...
line.clear();
}
The number of (re-)allocations is kept minimal, as line will grow only as needed to accommodate the input lines. Once a typical size is reached, allocations will become very rare, and once the largest line is read, they will disappear altogether. If read_line() supported the "convenient" interface, then the above loop would indeed look nicer - for example:
while let Some(line) = read_new_line(some_input)? {
// process the line
...
}
...but would require a new allocation and deallocation for each line. In throw-away or learning programs this can be perfectly fine, but BufRead is intended as a building block for efficient IO, so its read_line method favors performance over convenience.
In the book, rustaceans-to-be get to build a guessing game. In this guessing game, there's the following snippet:
let mut guess = String::new();
io::stdin().read_line(&mut guess)
.expect("Failed to read line");
Um... why would read_line() fail, I thought. And then found out the hard way: Instead of 50 I entered 5ß (German keyboards...) and... read line failed.
So I thought I'd fix it quickly.
match io::stdin().read_line(&mut guess) {
Ok(str) => str,
Err(_) => println!("Please only enter ASCII characters.");
}
That returned a type mismatch: Expected (), found usize
Ah, right! read_line() returns the number of entered bytes in the Ok result. But I don't want to do anything with that information so I replaced the Ok statement from above:
Ok(_) => {},
That works. But is this the right way to do it? I'm basically telling the program to run an empty code block on Ok, which I'd consider bad style in languages like Java, PHP, JavaScript etc.
Since you're only interested in one of the match arms, you can use an if let binding:
if let Err (_) = io::stdin().read_line(&mut guess) {
println!("Please only enter ASCII characters.");
}