Running functions based on user input in Rust - rust

I'm new to the Rust language and as I usually do when trying to pick up a language, I like to go through Euler Project questions. I want to get familiar with cargo and everything it offers, so I've created a cargo project called euler-project.
On startup, I want the program to ask the user which solution to run and have it run a function in the code that corresponds to the solution requested by the user.
I like to avoid huge chains of if / else if / else blocks, so I thought the match function would work well. Here's what I have.
use std::io;
fn main() {
// Solution selection. Every solution will be selectable here
let mut selection = String::new();
// Enum to hold every solved problem number for match control flow
enum Solutions {
P1, P2,
}
loop {
println!("Select the solution you would like to run. (Example: '32' would be Problem 32)");
io::stdin()
.read_line(&mut selection)
.expect("Input should be an integer.");
match selection {
Solutions::P1 => p1(),
Solutions::P2 => p2(),
}
}
}
fn p1() {
println!("p1")
}
fn p2() {
}
Currently this produces an error as follows:
...
21 | match selection {
| --------- this expression has type `std::string::String`
22 | Solutions::P1 => p1(),
| ^^^^^^^^^^^^^ expected struct `std::string::String`, found enum `main::Solutions`
What am I doing wrong here? If you know a better option for doing this type of control, please suggest it to me. I am also curious to know if there is anything similar to Python's interactive console mode that allows a user to run the code in the terminal, and to make function calls by simply typing function names and hitting enter.

You're comparing apples and oranges here. On the one hand, you have the string you have read from the user, and on the other hand you have values of type Solutions, but nowhere do you tell the compiler how to compare the two. The easiest way to do what you want is just to compare strings directly:
match selection.trim() {
"1" => p1(),
"2" => p2(),
_ => panic!("{} does not designate a valid problem!", selection),
}
Note the call to trim: the string returned by read_line includes the trailing newline, which you need to remove so that the comparisons will work.
Note also that you will need to call selection.clear() before read_line, otherwise the next iteration of the loop will append to the string instead of replacing it.

You can't match an enum with a String. You could try something like:
match selection.trim().parse::<i32>() {
Ok(x) if x == (Solutions::P1 as i32) => p1(),
Ok(x) if x == (Solutions::P2 as i32)=> p2(),
x => panic!{x},
}

Related

Why match object is borrowed in rust?

The code case is from rustlings 'quiz2.rs'. I known command in ‘for(string,command)’ is borrowed from vector iterator. The command is borrowed, but why the 'n' Append(n) is also borrowed?
pub fn transformer(input: Vec<(String, Command)>) -> Vec<String> {
// TODO: Complete the output declaration!
let mut output: Vec<String> = vec![];
for (string, command) in input.iter() {
// TODO: Complete the function body. You can do it!
match command {
Command::Uppercase => output.push(string.to_uppercase()),
Command::Trim => output.push(string.trim().to_string()),
Command::Append(n) => {
let can_mv_str = string.to_string() + &"bar".repeat(*n);
output.push(can_mv_str);
}
}
}
output
}
First, Vec::iter() returns an iterator over references to the elements of the vector, that is, &(String, Command).
Then, whenever you write a pattern for some specific structure, like the 2-element tuple (string, command) in the for loop, but the input is a reference to that structure, Rust matches "through" the reference and automatically gives you references to the elements (because it's not possible in general to not get references, since not every type is Copy).
So, the type of command is &Command. Then the same thing happens to the match command { and every variable binding in the match's pattern (that is, n) will be a reference too.
If you want to avoid this, what you have to do is explicitly write out matching against the references:
match command {
...
&Command::Append(n) => {
let can_mv_str = string.to_string() + &"bar".repeat(n);
output.push(can_mv_str);
}
}
Or, you can dereference the input to the match (this won't necessarily try to move out of the reference — as long as you don't bind any non-Copy values):
match *command {
...
Command::Append(n) => {
let can_mv_str = string.to_string() + &"bar".repeat(n);
output.push(can_mv_str);
}
}
Finally, if you want to completely avoid the magic and write out a program that is doing the whole thing explicitly, you also need to adjust the for pattern:
for &(ref string, ref command) in input.iter() {
The ref means "please don't try to move this value out of what I'm matching; just give me a reference to it. It's rarely seen in modern Rust because the automatic matching behavior I'm talking about makes it mostly unnecessary. This feature of Rust is called “match ergonomics”, because it saves you from writing a lot of & and ref all the time. But, as you've seen, it can lead to surprising behavior, and the old explicit style also lets you avoid dealing with needless references to Copy types like integers.
If you'd like to try writing Rust without ever using match ergonomics, to understand “what's really going on”, you can enable a Clippy restriction lint to mark any places where the pattern doesn't actually fit the type of what it's matching:
#[warn(clippy::pattern_type_mismatch)]
and run cargo clippy to see the new warnings. You'll probably find that there's quite a lot of patterns that are implicitly working on references!
This is because of RFC 2005. Before that, there used to be special syntax of ref and ref mut when you wanted to take a reference to an inner field in match.
What happens here is that your command is an &Command. You match on it but the arms are all Command. So command gets de-referenced automatically. But then, in Command::Append you take ownership of the inner n. This cannot happen as your command was a reference. So rust gives you a reference to n.
You can fix this in multiple ways. The easiest is to dereference the n yourself, like so:
match command {
Command::Append(&n) => ..., // n is owned here
...
}
This works when n is Copy. You can also do a let n = n.clone() in the match body itself if n is not Copy but is Clone.
You can also take ownership of command, like so:
match *command { // if Command is Copy
Command::Append(n) => ..., // n is owned here
...
}
// OR
match command.clone() { // if Command is Clone
Command::Append(n) => ..., // n is owned here
...
}
If you cannot do any of the above, then you will need to work with the reference itself or maybe change your iterator from input.iter() to input.into_iter() to get an owned Command from the start.

Why does `format_args!()` ignore truncation? How to truncate without allocation then?

Why does this work?
fn main() {
println!("{:.3}", "this is just a test");
}
prints => thi
While this doesn't?
fn main() {
println!("{:.3}", format_args!("this is just a test"));
}
prints => this is just a test
Here's a playground.
For a little more context, I’m interested in the reasoning behind it, and a way to do it without any allocations.
I'm developing a terminal game in Rust, where I have a write! which shows some statistics about the rendering and game loop, and that text can be quite long. Now that I read the terminal size and adjust its output accordingly, I need to truncate that output, but without any allocations.
I thought I was super clever when I refactored this:
write!(
stdout,
"{} ({} {} {}) {}",
...
)
into this:
write!(
stdout,
"{:.10}", // simulate only 10 cols in terminal.
format_args!(
"{} ({} {} {}) {}",
...
)
)
How unfortunate, it doesn’t work… How to do that without allocating a String?
For one thing, not every type obeys all formatting arguments:
println!("{:.3}", 1024);
1024
Second, format_args! serves as the backbone for all of the std::fmt utilities. From the docs on format_args:
This macro functions by taking a formatting string literal containing {} for each additional argument passed. format_args! prepares the additional parameters to ensure the output can be interpreted as a string and canonicalizes the arguments into a single type. Any value that implements the Display trait can be passed to format_args!, as can any Debug implementation be passed to a {:?} within the formatting string.
This macro produces a value of type fmt::Arguments. This value can be passed to the macros within std::fmt for performing useful redirection. All other formatting macros (format!, write!, println!, etc) are proxied through this one. format_args!, unlike its derived macros, avoids heap allocations.
You can use the fmt::Arguments value that format_args! returns in Debug and Display contexts as seen below. The example also shows that Debug and Display format to the same thing: the interpolated format string in format_args!.
let debug = format!("{:?}", format_args!("{} foo {:?}", 1, 2));
let display = format!("{}", format_args!("{} foo {:?}", 1, 2));
assert_eq!("1 foo 2", display);
assert_eq!(display, debug);
Looking at the source for impl Display for Arguments, it just ignores any formatting parameters. I couldn't find this explicitly documented anywhere, but I can think of a couple reasons for this:
The arguments are already considered formatted. If you really want to format a formatted string, use format! instead.
Since its used internally for multiple purposes, its probably better to keep this part simple; its already doing the format heavy-lifting. Attempting to make the thing responsible for formatting arguments itself accept formatting parameters sounds needlessly complicated.
I'd really like to truncate some output without allocating any Strings, would you know how to do it?
You can write to a fixed-size buffer:
use std::io::{Write, ErrorKind, Result};
use std::fmt::Arguments;
fn print_limited(args: Arguments<'_>) -> Result<()> {
const BUF_SIZE: usize = 3;
let mut buf = [0u8; BUF_SIZE];
let mut buf_writer = &mut buf[..];
let written = match buf_writer.write_fmt(args) {
// successfully wrote into the buffer, determine amount written
Ok(_) => BUF_SIZE - buf_writer.len(),
// a "failed to write whole buffer" error occurred meaning there was
// more to write than there was space for, return entire size.
Err(error) if error.kind() == ErrorKind::WriteZero => BUF_SIZE,
// something else went wrong
Err(error) => return Err(error),
};
// Pick a way to print `&buf[..written]`
println!("{}", std::str::from_utf8(&buf[..written]).unwrap());
Ok(())
}
fn main() {
print_limited(format_args!("this is just a test")).unwrap();
print_limited(format_args!("{}", 123)).unwrap();
print_limited(format_args!("{}", 'a')).unwrap();
}
thi
123
a
This was actually more involved than I originally thought. There might be a cleaner way to do this.
I found this word here
For non-numeric types, this can be considered a "maximum width". If the resulting string is longer than this width, then it is truncated down to this many characters and that truncated value is emitted with proper fill, alignment and width if those parameters are set.
For integral types, this is ignored.
For floating-point types, this indicates how many digits after the decimal point should be printed.
And format_args return type is std::fmt::Arguments,that is not String ,even though it looks like a string.
If you want to get same print contents,i think those code will work
/// unstable
println!("{:.3}", format_args!("this is just a test").as_str().unwrap());
println!("{:.3}", format_args!("this is just a test").to_string().as_str());

Formatting a const string in Rust [duplicate]

This extremely simple Rust program:
fn main() {
let c = "hello";
println!(c);
}
throws the following compile-time error:
error: expected a literal
--> src/main.rs:3:14
|
3 | println!(c);
| ^
In previous versions of Rust, the error said:
error: format argument must be a string literal.
println!(c);
^
Replacing the program with:
fn main() {
println!("Hello");
}
Works fine.
The meaning of this error isn't clear to me and a Google search hasn't really shed light on it. Why does passing c to the println! macro cause a compile time error? This seems like quite unusual behaviour.
This should work:
fn main() {
let c = "hello";
println!("{}", c);
}
The string "{}" is a template where {} will be replaced by the next argument passed to println!.
TL;DR If you don't care why and just want to fix it, see the sibling answer.
The reason that
fn main() {
let c = "hello";
println!(c);
}
Cannot work is because the println! macro looks at the string at compile time and verifies that the arguments and argument specifiers match in amount and type (this is a very good thing!). At this point in time, during macro evaluation, it's not possible to tell that c came from a literal or a function or what have you.
Here's an example of what the macro expands out to:
let c = "hello";
match (&c,) {
(__arg0,) => {
#[inline]
#[allow(dead_code)]
static __STATIC_FMTSTR: &'static [&'static str] = &[""];
::std::io::stdio::println_args(&::std::fmt::Arguments::new(
__STATIC_FMTSTR,
&[::std::fmt::argument(::std::fmt::Show::fmt, __arg0)]
))
}
};
I don't think that it's actually impossible for the compiler to figure this out, but it would probably take a lot of work with potentially little gain. Macros operate on portions of the AST and the AST only has type information. To work in this case, the AST would have to include the source of the identifier and enough information to determine it's acceptable to be used as a format string. In addition, it might interact poorly with type inference - you'd want to know the type before it's been picked yet!
The error message asks for a "string literal". What does the word "literal" mean? asks about what that means, which links to the Wikipedia entry:
a literal is a notation for representing a fixed value in source code
"foo" is a string literal, 8 is a numeric literal. let s = "foo" is a statement that assigns the value of a string literal to an identifier (variable). println!(s) is a statement that provides an identifier to the macro.
If you really want to define the first argument of println! in one place, I found a way to do it. You can use a macro:
macro_rules! hello {() => ("hello")};
println!(hello!());
Doesn't look too useful here, but I wanted to use the same formatting in a few places, and in this case the method was very helpful:
macro_rules! cell_format {() => ("{:<10}")}; // Pads with spaces on right
// to fill up 10 characters
println!(cell_format!(), "Foo");
println!(cell_format!(), 456);
The macro saved me from having to duplicate the formatting option in my code.
You could also, obviously, make the macro more fancy and take arguments if necessary to print different things with different arguments.
If your format string will be reused only a moderate number of times, and only some variable data will be changed, then a small function may be a better option than a macro:
fn pr(x: &str) {
println!("Some stuff that will always repeat, something variable: {}", x);
}
pr("I am the variable data");
Outputs
Some stuff that will always repeat, something variable: I am the variable data

How to pattern match on values inside a type implementing Deref, such as Box, without copying the contents?

I have data contained inside a Box, and would like to pattern match on it without accidentally copying the Box's contents from the heap to the stack; how do I do that?
Let's assume the following code:
enum SomeEnum {
SomeEntry,
AnotherEntry,
}
fn main() {
let boxed_value = Box::new(SomeEnum::AnotherEntry);
match *boxed_value {
SomeEnum::SomeEntry => {}
SomeEnum::AnotherEntry => {}
}
}
Does this copy the enum out of the box onto the stack and pattern match on that copy, or does it do the matching directly on the value pointed to by the box?
What about this variant?
use std::ops::Deref;
enum SomeEnum {
SomeEntry,
AnotherEntry,
}
fn main() {
let boxed_value = Box::new(SomeEnum::AnotherEntry);
match boxed_value.deref() {
SomeEnum::SomeEntry => {}
SomeEnum::AnotherEntry => {}
}
}
It seems that simply dereferencing a box does not automatically create a copy, otherwise one would not be able to create a reference to the contained value by using let x = &*boxed_value. This leads to a question about this syntax:
enum SomeEnum {
SomeEntry,
AnotherEntry,
}
fn main() {
let boxed_value = Box::new(SomeEnum::AnotherEntry);
match &*boxed_value {
SomeEnum::SomeEntry => {}
SomeEnum::AnotherEntry => {}
}
}
First: in Rust, there are no implicit costly copies, unlike in, for example, C++. Whereas in C++, the default action is "deep copy" (via copy constructor or similar), the default action in Rust is moving. A move is a shallow copy which (a) is usually very small and cheap and (b) can be removed by the optimizer in most cases. To get deep clones in Rust you have manually use .clone(). If you don't do that, you usually don't really have to worry about this.
Second: matching on an enum only looks at the discriminant of that enum (unless you bind enum fields, see below). That's the "tag" or the "metadata" which specifies which variant of the enum is stored in a value. That tag is tiny: it fits in 8 bits in almost all cases (enums with more than 256 variants are rare). So you don't need to worry about that. And in your case, we have a C-like enum without any fields. So the enum only stores the tag and hence is tiny, too.
So what about enum fields that might be costly to copy? Like this:
enum SomeEnum {
SomeEntry(String),
AnotherEntry,
}
let boxed_value = Box::new(SomeEnum::AnotherEntry);
match *boxed_value {
SomeEnum::SomeEntry(s) => drop::<String>(s), // make sure we own the string
SomeEnum::AnotherEntry => {},
}
So in this case one variant stores a String. Since deep-copying a string is somewhat costly, Rust won't do it implicitly. In the match arm we try to drop s and assert it's a String. That means we (meaning: the body of the match arm) own the string. So, if the match arm owns it but we didn't get the owned value from cloning it, that means that the outer function doesn't own it anymore. And in fact, if you try to use boxed_value after the match, you will get move errors from the compiler. So again, either you get a compiler error or no bad things automatically happen.
Furthermore, you can write SomeEnum::SomeEntry(ref s) in the match. In that case, the string is bound by reference to s (so the drop() call won't work anymore). In that case, we never move from boxed_value. This is something I call "deferred moving", but I'm not sure if that's an official term for it. But it just means: when pattern matching, the input value is not moved at all until a binding in the pattern moves from it.
Lastly, please take a look at this code and the generated assembly. The assembly is optimal. So once again: while you might be worried about accidental clones when you come from the C++ world, this is not really something you need to worry about in Rust.

Variables with the same name inside Some(T) in Rust

I'm fairly new to Rust so I came across this piece of code in the official Guide
let input = io::stdin().read_line()
.ok()
.expect("Failed to read line");
let input_num: Option<uint> = from_str(input.as_slice());
let num = match input_num {
Some(num) => num,
None => {
println!("Please input a number!");
return;
}
};
While the understand the first two statements (on input and inputnum), I'm not quite sure about the match statement. So I checked the documentation which shows that Option<T> can take two values , either None or Some(T) for some (object?) T. So I tested the following code:
io::println(
match input_num {
Some(num) => "somenum",
None => {
println!("Please input a number only!");
return;
}
}
);
This code works as expected; it prints somenum if you enter a number and otherwise it prints the error message. However, the compiler gives a warning stating: warning: unused variable:num, #[warn(unused_variable)] on by default. This confirmed my suspicions that the num inside the `match is used as a variable.
Question: How is it possible that rust does not complain about (in the Guide's example) having two variables with the same name num? Or does it "hand over" the pointer to the inside num to the outside num?
Also in the case of an empty return what exactly is returned? I'm guessing it is unit () because it is mentioned here that
functions without a -> ... implicitly have return type ()
Edit: Sorry for missing the obvious point. The return directly exits the function without bothering to put anything into num.
P.S. I noticed that using cargo build to compile does not give warnings the second time around (not making any changes). Does cargo keep tracking of versions or something?
Do you have any experiences with Java or C#? Many mainstream programing languages allows you to shadow a variable with another variable with the same name in a new block scope. For example, take a look at this C# code:
using System;
public class Test
{
public static void Main()
{
int x = 10;
{
int x = 20;
Console.WriteLine(x);
}
Console.WriteLine(x);
}
}
http://ideone.com/OuMlc8
In fact Rust is more flexible in terms of shadowing: you can shadow variables as many times as you want without explicitly making a brace block.
fn main() {
let i = 10i32;
let i = "foo";
println!("{}", i);
}
http://is.gd/CUHUOL
Here, the first i and the second i have no relationships. We just lose a way to use (refer to) the first i.
This confirmed my suspicions that the num inside the `match is used as a variable.
Yes, pattern matching can introduce new variables. But the new variable num introduced by pattern matching has no direct relationship with the outer num whose value is being given by the match expression.
I can translate your Rust code into less idiomatic Rust to illustrate what was happening:
let num =
if input_num.is_some() {
let num = input_num.unwrap();
num
} else {
println!("Please input a number!");
return;
}
;
As for not observing warnings from cargo build, I suspect it was because Cargo had already built .o from your code and didn't bother to repeat the same job twice, knowing that there was no change in your code.

Resources