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
Related
Let us say I have a function like follows:
fn log(msg: &str) {
//fancy_output
println!("{}", msg)
}
Now, if I want to log a variable using the function, I must do it like so:
let x = 5;
log(&format!("{:?}", x)); // Assume some complex data type which implements Debug
Clearly this is a lot of boilerplate. I could remove the & by making the argument a string, but that does not remove my bigger problem: using format!() everywhere.
How can I write a function/macro such that I can do the following or similar:
let x = 5;
log("{:?}", x) // Assume some complex data type which implements Debug
I know a place to start would be looking at the format! source code, but it is quite hard to understand for a beginner like me and how I might implement it here.
Do I use some fancy macro or is there a simpler way?
format! is a macro, not a function, which is why it is able to work with variable number of arguments. You can do the same with a declarative macro like this:
macro_rules! log {
($($args: tt)*) => {
println!($($args)*);
}
}
The $($args: tt)* means that the macro accepts zero or more (*) of any kind of token (tt). Then it just passes these on to the println macro.
Which you can call like this:
fn main() {
let x = 5;
log!("{:?}", x);
}
Like following code,
it does working to print values with formatted print, when values are primitive values or struct(with derive debug attribute), or something.
But I can't print values when values are struct fields.
#[derive(Debug)]
struct Point<T> {
x: T,
y: T,
}
fn main() {
let a = 3;
let p = Point { x: 5, y: 10 };
println!("{}", a); // Working
println!("{a}"); // Working
println!("{:?}", p); // Working
println!("{p:?}"); // Working
println!("{} {}", p.x, p.y); // Working
println!("{p.x} {p.y}"); // Not working
}
The error message is following.
error: invalid format string: expected `'}'`, found `'.'`
--> src/main.rs:18:17
|
18 | println!("{p.x} {p.y}"); // Not working
| - ^ expected `}` in format string
| |
| because of this opening brace
|
= note: if you intended to print `{`, you can escape it using `{{`
error: could not compile `rust-ex` due to previous error
I think that the type of p.x and p.y is i32 so they can printed with formatted print but it doesn't.
Is there any way to print struct fields with formatter print? Or is there anything need to implement?
Your problem is not a formatting problem, just an issue with what exactly println! accepts in its formatting string.
Contrary to what you may experience in other languages, the part between braces in the literal string in a println! is not a string escape, meaning that you could put any (printable) Rust expression. Instead, you should see it as a named parameter. Therefore, it can only be a variable name. println! also allows you to mimic variable definition if you don't already have a variable with that name, like this:
println!("{px}", px = p.x);
Another similar but different issue is trying to println! when you have a Rust variable that is an underscore:
let _ = 2;
println!("Value of _ is {_}");
The error is:
invalid format string: invalid argument name `_`
...
println!("Value of _ is {_}");
^ invalid argument name in format string
This is probably because the underscore is meant to be ignored
The underscore (_) is a reserved identifier in Rust and serves different purposes depending on the context. It usually means that something is ignored.
Other sites explain how in rust, the underscore does "not bind to the variable"; or "does not have ownership of the object"
See #jthulhu's comment --not only is _ meant to be ignored in Rust, the _ variable cannot be used in Rust; therefore isn't even allocated (that explains my error messages). This is different from other programming languages, where the _ variable is just a convention to signify the _ variable is meant to be ignored but could be used. In Rust, as #jthulhu says: "Basically, doing let _ = 3; will result in absolutely nothing even without optimizations"
I know the OP already found the best accepted answer. I just want to offer this answer in case other folks search for "invalid format string" or "invalid argument name _" and find this SO question.
If you tried a workaround like:
println!("Value of _ is {}", _);
Then you get a new error, reinforcing the idea that the underscore variable is never meant to be used:
in expressions, `_` can only be used on the left-hand side of an assignment
`_` not allowed here
So the underscore variable is allowed on the left-hand side of an assignment as in my code above, or this underscore expression where the _ signifies a placeholder in a destructuring assignment, but you can't reference the underscore variable later, including in println!. The only solution is to use a different variable name.
I am trying to parse a single char variable into ASCII value, but all the time I am getting an error.
Basing on answer of hansaplast from this post Parsing a char to u32 I thought this code should work:
let char_variable = 'a';
let shoud_be_u32_varaible = a.to_digit(10).unwrap();
But this code will always throw this error:
thread 'main' panicked at 'called Option::unwrap() on a None value'
For this, code example (example provided in answer of hansaplast):
let a = "29";
for c in a.chars() {
println!("{:?}", c.to_digit(10));
}
This .to_digit() method will work.
In both cases I am using on .to_digit(10) on variables which are type of char, but for my example this code throws an error and for the code from hansaplast this works. Can someone explain to me what is the difference between those examples and what I am doing wrong because now I am super confused?
Both examples can be found there: Rust playground example
Is using casting in this case will be ok?
let c = 'a';
let u = c as u32 - 48;
If not, can you tell me, what is recommended of doing this?
Okay, I think you are confusing type casting and integer parsing.
to_digit is an integer parsing method. It takes the character and given a radix determines its value in that base. So 5 in base 10 is 5 and is stored as 00000101. 11 in base 15 is stored in memory as 00010000.
Type casting of primitives in rust like 'c' as u32 is probably more what you are after. It's distinct from integer parsing in the sense that you don't care about the "meaning" of the number what you care about is the value of the bits that represent it in memory. This means that the character 'c' is stored as 1100011 (99).
If you only care about ascii characters you should also check char.is_ascii() before doing your conversion. That way you can store your results in a u8 instead of a u32
fn print_ascii_values_of_characters(string: &str) {
for c in string.chars() {
if c.is_ascii() {
println!("{:b}", c as u8) // :b prints the binary representation
}
}
}
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());
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},
}