In Swift, ! means to unwrap an optional (possible value).
println! is not a function, it is a macro. Macros use ! to distinguish them from normal method calls. The documentation contains more information.
See also:
What is the difference between macros and functions in Rust?
Rust uses the Option type to denote optional data. It has an unwrap method.
Rust 1.13 added the question mark operator ? as an analog of the try! macro (originally proposed via RFC 243).
An excellent explanation of the question mark operator is in The Rust Programming Language.
fn foo() -> Result<i32, Error> {
Ok(4)
}
fn bar() -> Result<i32, Error> {
let a = foo()?;
Ok(a + 4)
}
The question mark operator also extends to Option, so you may see it used to unwrap a value or return None from the function. This is different from just unwrapping as the program will not panic:
fn foo() -> Option<i32> {
None
}
fn bar() -> Option<i32> {
let a = foo()?;
Some(a + 4)
}
println! is a macro in rust, that means that rust will rewrite the code for you at compile time.
For example this:
fn main() {
let x = 5;
println!("{}", x);
}
Will be converted to something like this at compile time:
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std;
fn main() {
let x = 5;
{
::std::io::_print(::core::fmt::Arguments::new_v1(
&["", "\n"],
&match (&x,) {
(arg0,) => [::core::fmt::ArgumentV1::new(
arg0,
::core::fmt::Display::fmt,
)],
},
));
};
}
*Notice that the &x is passed as a reference.
It's a macro because it does things that functions can't do:
It parses the format string at compile time, and generates type safe code
It has a variable number of arguments
It has named arguments ("keyword arguments")
println!("My name is {first} {last}", first = "John", last = "Smith");
sources:
https://doc.rust-lang.org/rust-by-example/hello/print.html.
https://www.reddit.com/r/rust/comments/4qor4o/newb_question_why_is_println_a_macro/
Does println! borrow or own the variable?
Related
As the title says, I want to convert a string literal into code. So, naturally, I come up with macro:
// main.rs
use quote::quote;
use syn::ExprClosure;
// declare a macro to expand the entire input TokenStream as a token tree.
macro_rules! foo {
($t:tt) => {
$t
};
}
fn main() {
let code = "|x:&i32|x+1";
// parse string literal to syn::ExprClosure type.
let expr = syn::parse_str::<ExprClosure>(code).unwrap();
// return a value has a TokenStream type.
let expr_ts = quote! {
let slice = vec![1,2,3];
let slice2: Vec<i32> = slice.iter()
.map(#expr)
.collect();
println!("{:#?}",slice);
};
// call foo! to expand `expr_ts`
foo!(expr_ts);
}
which can be compiled perfectly, printing, however, nothing at all.
As far as I could understand, the reason why it prints nothing is in that $t in foo! is possibly not expanded as what I want it to. So I turned to this to try figure out if the type of $t went wrong:
macro_rules! foo {
($t:tt) => {
println!("{:#?}", $t);
};
}
which successfully printed the syntax tree of $t(which has a syn::ExprClosure type).
Update:
After doing some research on macro, I found that the problem was likely a misuse (or a misunderstanding) of different macro types: procedural macro vs. declarative macro.
So I refactor the code, which turns out to be a success:
// another_crate::lib
#[proc_macro]
pub fn foo(item : TokenStream) -> TokenStream {
let code = "|x:&i32|x+1";
let expr = syn::parse_str::<ExprClosure>(code).unwrap();
let expr_ts = quote! {
let slice = vec![1,2,3];
let slice2: Vec<i32> = slice.iter()
.map(#expr)
.collect();
println!("{:?}",slice2);
};
TokenStream::from(expr_ts)
}
// main.rs
use another_crate::foo;
fn main() {
foo!();
}
// output
// [2, 3, 4]
The quote! macro evaluates to an expression of type proc_macro2::TokenStream. Meanwhile Rust procedural macros are expected to return the type proc_macro::TokenStream.
The difference between the two types is that proc_macro types are entirely specific to procedural macros and cannot ever exist in code outside of a procedural macro, while proc_macro2 types may exist anywhere including tests and non-macro code like main.rs and build.rs.
As noted above (quote's doc), we can't use proc_macro::TokenStream in main.rs,which was exactly what I did in the first place: I used quote! in main.rs which returns a proc_macro2::TokenStream and expected that it would be parsed and expanded by compiler, which is not possible because the compiler accepts TokenStream input only if it is of proc_macro from another_crate(which is a procedural macro lib),not of proc_macro2 from main.rs.
Now the question here is that if I can implement the convertion just through declarative macro? It seems that procedural macros don't accept any variable as arguments, which means you can only hardcode string literal.
Really appreciate any replies regarding my concern.
Thanks.
Problem:
Im new to Rust, and im trying to implement a macro which simulates sscanf from C.
So far it works with any numeric types, but not with strings, as i am already trying to parse a string.
macro_rules! splitter {
( $string:expr, $sep:expr) => {
let mut iter:Vec<&str> = $string.split($sep).collect();
iter
}
}
macro_rules! scan_to_types {
($buffer:expr,$sep:expr,[$($y:ty),+],$($x:expr),+) => {
let res = splitter!($buffer,$sep);
let mut i = 0;
$(
$x = res[i].parse::<$y>().unwrap_or_default();
i+=1;
)*
};
}
fn main() {
let mut a :u8; let mut b :i32; let mut c :i16; let mut d :f32;
let buffer = "00:98;76,39.6";
let sep = [':',';',','];
scan_to_types!(buffer,sep,[u8,i32,i16,f32],a,b,c,d); // this will work
println!("{} {} {} {}",a,b,c,d);
}
This obviously wont work, because at compile time, it will try to parse a string slice to str:
let a :u8; let b :i32; let c :i16; let d :f32; let e :&str;
let buffer = "02:98;abc,39.6";
let sep = [':',';',','];
scan_to_types!(buffer,sep,[u8,i32,&str,f32],a,b,e,d);
println!("{} {} {} {}",a,b,e,d);
$x = res[i].parse::<$y>().unwrap_or_default();
| ^^^^^ the trait `FromStr` is not implemented for `&str`
What i have tried
I have tried to compare types using TypeId, and a if else condition inside of the macro to skip the parsing, but the same situation happens, because it wont expand to a valid code:
macro_rules! scan_to_types {
($buffer:expr,$sep:expr,[$($y:ty),+],$($x:expr),+) => {
let res = splitter!($buffer,$sep);
let mut i = 0;
$(
if TypeId::of::<$y>() == TypeId::of::<&str>(){
$x = res[i];
}else{
$x = res[i].parse::<$y>().unwrap_or_default();
}
i+=1;
)*
};
}
Is there a way to set conditions or skip a repetition inside of a macro ? Or instead, is there a better aproach to build sscanf using macros ? I have already made functions which parse those strings, but i couldnt pass types as arguments, or make them generic.
Note before the answer: you probably don't want to emulate sscanf() in Rust. There are many very capable parsers in Rust, so you should probably use one of them.
Simple answer: the simplest way to address your problem is to replace the use of &str with String, which makes your macro compile and run. If your code is not performance-critical, that is probably all you need. If you care about performance and about avoiding allocation, read on.
A downside of String is that under the hood it copies the string data from the string you're scanning into a freshly allocated owned string. Your original approach of using an &str should have allowed for your &str to directly point into the data that was scanned, without any copying. Ideally we'd like to write something like this:
trait MyFromStr {
fn my_from_str(s: &str) -> Self;
}
// when called on a type that impls `FromStr`, use `parse()`
impl<T: FromStr + Default> MyFromStr for T {
fn my_from_str(s: &str) -> T {
s.parse().unwrap_or_default()
}
}
// when called on &str, just return it without copying
impl MyFromStr for &str {
fn my_from_str(s: &str) -> &str {
s
}
}
Unfortunately that doesn't compile, complaining of a "conflicting implementation of trait MyFromStr for &str", even though there is no conflict between the two implementations, as &str doesn't implement FromStr. But the way Rust currently works, a blanket implementation of a trait precludes manual implementations of the same trait, even on types not covered by the blanket impl.
In the future this will be resolved by specialization. Specialization is not yet part of stable Rust, and might not come to stable Rust for years, so we have to think of another solution. In case of macro usage, we can just let the compiler "specialize" for us by creating two traits with the same name. (This is similar to the autoref-based specialization invented by David Tolnay, but even simpler because it doesn't require autoref resolution to work, as we have the types provided explicitly.)
We create separate traits for parsed and unparsed values, and implement them as needed:
trait ParseFromStr {
fn my_from_str(s: &str) -> Self;
}
impl<T: FromStr + Default> ParseFromStr for T {
fn my_from_str(s: &str) -> T {
s.parse().unwrap_or_default()
}
}
pub trait StrFromStr {
fn my_from_str(s: &str) -> &str;
}
impl StrFromStr for &str {
fn my_from_str(s: &str) -> &str {
s
}
}
Then in the macro we just call <$y>::my_from_str() and let the compiler generate the correct code. Since macros are untyped, this works because we never need to provide a single "trait bound" that would disambiguate which my_from_str() we want. (Such a trait bound would require specialization.)
macro_rules! scan_to_types {
($buffer:expr,$sep:expr,[$($y:ty),+],$($x:expr),+) => {
#[allow(unused_assignments)]
{
let res = splitter!($buffer,$sep);
let mut i = 0;
$(
$x = <$y>::my_from_str(&res[i]);
i+=1;
)*
}
};
}
Complete example in the playground.
I was reading up code for anyhow crate in Rust. There is a particular line I don't fully grasp:
{
let vtable = &ErrorVTable { ... };
construct(vtable, ...);
}
fn construct(vtable: &'static ErrorVTable, ...);
We seem to create an ErrorVTable struct, and return a reference to it which has lifetime `static. I'd expect compiler to create a struct on function stack, and return a reference to it, causing weird memory issues.
But it appears like compiler detects that this variable for all possible E inferred on compile time and somehow creates static variables for them? How does this actually work?
Consider this simplified code:
struct Foo {
x: i32
}
fn test(_: &'static Foo) {}
fn main() {
let f = Foo{ x: 42 };
test(&f);
}
As expected, it does not compile, with the message:
f does not live long enough
However this slightly variation does compile:
fn main() {
let f = &Foo{ x: 42 };
test(f);
}
The difference is that in the former, the Foo object is local, with a local lifetime, so no 'static reference can be built. But in the latter, the actual object is a static constant so it has static lifetime, and f is just a reference to it.
To help see the difference, consider this other equivalent code:
const F: Foo = Foo{ x: 42 };
fn main() {
test(&F);
}
Or if you use an actual constant literal:
fn test_2(_: &'static i32) {}
fn main() {
let i = &42;
test_2(&i);
}
Naturally, this only works if all the arguments of the Foo construction are constant. If any value is not constant, then the compiler will silently switch to a local temporary instead of a static constant and you will lose the 'static lifetime.
The precise rules for this constant promotion, as it is sometimes called, are a bit complicated and may be extended in newer compiler versions.
I am confused with borrowing and ownership. In the Rust documentation about reference and borrowing
let mut x = 5;
{
let y = &mut x;
*y += 1;
}
println!("{}", x);
They say
println! can borrow x.
I am confused by this. If println! borrows x, why does it pass x not &x?
I try to run this code below
fn main() {
let mut x = 5;
{
let y = &mut x;
*y += 1;
}
println!("{}", &x);
}
This code is identical with the code above except I pass &x to println!. It prints '6' to the console which is correct and is the same result as the first code.
The macros print!, println!, eprint!, eprintln!, write!, writeln! and format! are a special case and implicitly take a reference to any arguments to be formatted.
These macros do not behave as normal functions and macros do for reasons of convenience; the fact that they take references silently is part of that difference.
fn main() {
let x = 5;
println!("{}", x);
}
Run it through rustc -Z unstable-options --pretty expanded on the nightly compiler and we can see what println! expands to:
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std;
fn main() {
let x = 5;
{
::std::io::_print(::core::fmt::Arguments::new_v1(
&["", "\n"],
&match (&x,) {
(arg0,) => [::core::fmt::ArgumentV1::new(
arg0,
::core::fmt::Display::fmt,
)],
},
));
};
}
Tidied further, it’s this:
use std::{fmt, io};
fn main() {
let x = 5;
io::_print(fmt::Arguments::new_v1(
&["", "\n"],
&[fmt::ArgumentV1::new(&x, fmt::Display::fmt)],
// ^^
));
}
Note the &x.
If you write println!("{}", &x), you are then dealing with two levels of references; this has the same result because there is an implementation of std::fmt::Display for &T where T implements Display (shown as impl<'a, T> Display for &'a T where T: Display + ?Sized) which just passes it through. You could just as well write &&&&&&&&&&&&&&&&&&&&&&&x.
Early 2023 update:
Since mid-2021, the required invocation has been rustc -Zunpretty=expanded rather than rustc -Zunstable-options --pretty=expanded.
Since 2023-01-28 or so (https://github.com/rust-lang/rust/pull/106745), format_args! is part of the AST, and so the expansion of println!("{}", x) is ::std::io::_print(format_args!("{0}\n", x));, not exposing the Arguments::new_v1 construction and &x aspects. This is good for various reasons (read #106745’s description), but ruins my clear demonstration here that x was only taken by reference. (This is why I’ve added this as a note at the end rather than updating the answer—since it no longer works.)
I am confused with borrowing and ownership. In the Rust documentation about reference and borrowing
let mut x = 5;
{
let y = &mut x;
*y += 1;
}
println!("{}", x);
They say
println! can borrow x.
I am confused by this. If println! borrows x, why does it pass x not &x?
I try to run this code below
fn main() {
let mut x = 5;
{
let y = &mut x;
*y += 1;
}
println!("{}", &x);
}
This code is identical with the code above except I pass &x to println!. It prints '6' to the console which is correct and is the same result as the first code.
The macros print!, println!, eprint!, eprintln!, write!, writeln! and format! are a special case and implicitly take a reference to any arguments to be formatted.
These macros do not behave as normal functions and macros do for reasons of convenience; the fact that they take references silently is part of that difference.
fn main() {
let x = 5;
println!("{}", x);
}
Run it through rustc -Z unstable-options --pretty expanded on the nightly compiler and we can see what println! expands to:
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std;
fn main() {
let x = 5;
{
::std::io::_print(::core::fmt::Arguments::new_v1(
&["", "\n"],
&match (&x,) {
(arg0,) => [::core::fmt::ArgumentV1::new(
arg0,
::core::fmt::Display::fmt,
)],
},
));
};
}
Tidied further, it’s this:
use std::{fmt, io};
fn main() {
let x = 5;
io::_print(fmt::Arguments::new_v1(
&["", "\n"],
&[fmt::ArgumentV1::new(&x, fmt::Display::fmt)],
// ^^
));
}
Note the &x.
If you write println!("{}", &x), you are then dealing with two levels of references; this has the same result because there is an implementation of std::fmt::Display for &T where T implements Display (shown as impl<'a, T> Display for &'a T where T: Display + ?Sized) which just passes it through. You could just as well write &&&&&&&&&&&&&&&&&&&&&&&x.
Early 2023 update:
Since mid-2021, the required invocation has been rustc -Zunpretty=expanded rather than rustc -Zunstable-options --pretty=expanded.
Since 2023-01-28 or so (https://github.com/rust-lang/rust/pull/106745), format_args! is part of the AST, and so the expansion of println!("{}", x) is ::std::io::_print(format_args!("{0}\n", x));, not exposing the Arguments::new_v1 construction and &x aspects. This is good for various reasons (read #106745’s description), but ruins my clear demonstration here that x was only taken by reference. (This is why I’ve added this as a note at the end rather than updating the answer—since it no longer works.)