Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a macro type argument inside a generated function

Tags:

macros

rust

I'm trying to implement a macro which implements the Add trait for a struct, like so:

macro_rules! implement_add {
    ($t:ty) => {
        impl std::ops::Add for $t {
            type Output = $t;
            fn add(self, rhs: $t) -> $t {
                $t(self.0 + rhs.0)        // error on this line
            }
        }
    }
}

pub struct Length(f64);

implement_add!(Length);

fn main() {}

However, this gives an error on the indicated line:

<anon>:6:17: 6:19 error: unexpected token: `Length`
<anon>:6                 $t(self.0 + rhs.0)        // error on this line
                         ^~

This makes no sense to me. Especially since, if I replace $t there with Length, it compiles fine. Am I doing something wrong in my macro?

Playground: http://is.gd/EIEKub

like image 959
Benjamin Lindley Avatar asked Sep 28 '22 01:09

Benjamin Lindley


People also ask

Can we pass a macro as an argument to a function?

You can't pass as function argument. But if function is a macro this is possible.

Can we define a macro inside a function?

You can use it inside a function, but it is not scoped to the function. So, in your example, the second definitions of a macro will be a redefinition and generate an error.

How do you use macros in arguments?

To define a macro that uses arguments, you insert parameters between the pair of parentheses in the macro definition that make the macro function-like. The parameters must be valid C identifiers, separated by commas and optionally whitespace.


1 Answers

You've stumbled on a subtle bit of Rust's type system. Length is a type, but Length() is a function. These exist in different namespaces.

One work around is to extend your macro to accept a type and a function:

macro_rules! implement_add {
    ($t:ty, $c:ident) => {
        impl std::ops::Add for $t {
            type Output = $t;
            fn add(self, rhs: $t) -> $t {
                $c(self.0 + rhs.0)        // error on this line
            }
        }
    }
}

pub struct Length(f64);

implement_add!(Length, Length);

fn main() {}
like image 122
Shepmaster Avatar answered Dec 09 '22 23:12

Shepmaster