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.