如何在Rust中扩展C/C++宏以消除冗余代码

huangapple go评论70阅读模式
英文:

How to expand the C\C++ macro in Rust to remove redundant code

问题

Sure, here's the translated code in Rust:

use std::fmt;

struct ObjAttribution {
    id: &'static str,
    attribute_type: Attribute,
}

struct Attribute {
    file_name: &'static str,
    code: i32,
    companion_name: &'static str,
}

impl ObjAttribution {
    const fn new(id: &'static str, file_name: &'static str, code: i32, companion_name: &'static str) -> Self {
        ObjAttribution {
            id,
            attribute_type: Attribute {
                file_name,
                code,
                companion_name,
            },
        }
    }
}

impl fmt::Debug for ObjAttribution {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?} --> {:?} --> {} --> {:?}", self.id, self.attribute_type.file_name, self.attribute_type.code, self.attribute_type.companion_name)
    }
}

macro_rules! CONST_ATTRIBUTE {
    ($id:ident, $x:literal, $y:expr, $z:literal) => {
        const $id: ObjAttribution = ObjAttribution::new(stringify!($id), $x, $y, $z);
    };
}

CONST_ATTRIBUTE!(USER_IO, "user_info.txt", 64, "user_companion.txt");
CONST_ATTRIBUTE!(USER_IO_1, "user_info_1.txt", 65, "user_companion_1.txt");
CONST_ATTRIBUTE!(USER_IO_2, "user_info_2.txt", 66, "user_companion_2.txt");
CONST_ATTRIBUTE!(USER_IO_3, "user_info_3.txt", 67, "user_companion_3.txt");
CONST_ATTRIBUTE!(USER_IO_4, "user_info_4.txt", 68, "user_companion_4.txt");
CONST_ATTRIBUTE!(USER_IO_5, "user_info_5.txt", 69, "user_companion_5.txt");
CONST_ATTRIBUTE!(USER_IO_6, "user_info_6.txt", 70, "user_companion_6.txt");
CONST_ATTRIBUTE!(USER_IO_7, "user_info_7.txt", 71, "user_companion_7.txt");
CONST_ATTRIBUTE!(USER_IO_8, "user_info_8.txt", 72, "user_companion_8.txt");

fn main() {
    println!("{:?}\n{:?}\n{:?}\n{:?}\n{:?}\n{:?}\n{:?}\n{:?}", USER_IO, USER_IO_1, USER_IO_2, USER_IO_3, USER_IO_4, USER_IO_5, USER_IO_6, USER_IO_7);
}

In this Rust code, we've defined a similar data structure and macros to the C++ code, allowing you to create and use constant attributes. The const keyword is used to create constant objects, and we use the stringify! macro to obtain the string representations of identifiers.

Please note that in Rust, macros are used differently than in C++, and you'll need to define a macro using macro_rules! and then use it with the $ symbol to create constant attributes.

The fmt::Debug trait is implemented to enable printing of the attributes using println! in the main function, similar to your C++ code.

英文:

I have a this code in C++ which is expanding some const code.

#include &lt;iostream&gt;
#include &lt;string&gt;

struct ObjAttribution {
    std::string id;
    struct attribute {
        std::string file_name;
        int code;
        std::string companion_name;
        attribute(std::string f, int c, std::string cn) : file_name(f), code(c), companion_name(cn) {}
    } attribute_type;
    ObjAttribution(std::string i, std::string f, int c, std::string cn)
    : id(i)
    , attribute_type(f, c, cn) {}
};

#define CONST_ATTRIBUTE(id, x, y, z) const ObjAttribution id(#id, #x, y, #z);
#define _x_(id, x, y, z) CONST_ATTRIBUTE(id, x, y, z)

// this will be great if I can convert something similar to this in rust - internally it should be creating const global object
_x_(USER_IO, user_info.txt, 64, user_companion.txt)  
_x_(USER_IO_1, user_info_1.txt, 65, user_companion_1.txt)
_x_(USER_IO_2, user_info_2.txt, 66, user_companion_2.txt)
_x_(USER_IO_3, user_info_3.txt, 67, user_companion_3.txt)
_x_(USER_IO_4, user_info_4.txt, 68, user_companion_4.txt)
_x_(USER_IO_5, user_info_5.txt, 69, user_companion_5.txt)
_x_(USER_IO_6, user_info_6.txt, 70, user_companion_6.txt)
_x_(USER_IO_7, user_info_7.txt, 71, user_companion_7.txt)
_x_(USER_IO_8, user_info_8.txt, 72, user_companion_8.txt)

int main() {

    std::cout &lt;&lt; USER_IO_1.id &lt;&lt; &quot; --&gt; &quot; &lt;&lt; USER_IO_1.attribute_type.file_name &lt;&lt; &quot; --&gt; &quot; &lt;&lt; USER_IO_1.attribute_type.code &lt;&lt;  &quot; --&gt; &quot; &lt;&lt; USER_IO_1.attribute_type.companion_name &lt;&lt; &quot;\n&quot;;
    std::cout &lt;&lt; USER_IO_2.id &lt;&lt; &quot; --&gt; &quot; &lt;&lt; USER_IO_2.attribute_type.file_name &lt;&lt; &quot; --&gt; &quot; &lt;&lt; USER_IO_2.attribute_type.code &lt;&lt;  &quot; --&gt; &quot; &lt;&lt; USER_IO_2.attribute_type.companion_name &lt;&lt; &quot;\n&quot;;
    std::cout &lt;&lt; USER_IO_3.id &lt;&lt; &quot; --&gt; &quot; &lt;&lt; USER_IO_3.attribute_type.file_name &lt;&lt; &quot; --&gt; &quot; &lt;&lt; USER_IO_3.attribute_type.code &lt;&lt;  &quot; --&gt; &quot; &lt;&lt; USER_IO_3.attribute_type.companion_name &lt;&lt; &quot;\n&quot;;
    std::cout &lt;&lt; USER_IO_4.id &lt;&lt; &quot; --&gt; &quot; &lt;&lt; USER_IO_4.attribute_type.file_name &lt;&lt; &quot; --&gt; &quot; &lt;&lt; USER_IO_4.attribute_type.code &lt;&lt;  &quot; --&gt; &quot; &lt;&lt; USER_IO_4.attribute_type.companion_name &lt;&lt; &quot;\n&quot;;
    std::cout &lt;&lt; USER_IO_5.id &lt;&lt; &quot; --&gt; &quot; &lt;&lt; USER_IO_5.attribute_type.file_name &lt;&lt; &quot; --&gt; &quot; &lt;&lt; USER_IO_5.attribute_type.code &lt;&lt;  &quot; --&gt; &quot; &lt;&lt; USER_IO_5.attribute_type.companion_name &lt;&lt; &quot;\n&quot;;
    std::cout &lt;&lt; USER_IO_6.id &lt;&lt; &quot; --&gt; &quot; &lt;&lt; USER_IO_6.attribute_type.file_name &lt;&lt; &quot; --&gt; &quot; &lt;&lt; USER_IO_6.attribute_type.code &lt;&lt;  &quot; --&gt; &quot; &lt;&lt; USER_IO_6.attribute_type.companion_name &lt;&lt; &quot;\n&quot;;
    std::cout &lt;&lt; USER_IO_7.id &lt;&lt; &quot; --&gt; &quot; &lt;&lt; USER_IO_7.attribute_type.file_name &lt;&lt; &quot; --&gt; &quot; &lt;&lt; USER_IO_7.attribute_type.code &lt;&lt;  &quot; --&gt; &quot; &lt;&lt; USER_IO_7.attribute_type.companion_name &lt;&lt; &quot;\n&quot;;

    return 0;
}

I am wondering how can I convert that in Rust. I want to do the processing in the compile time rather than in the runtime. I want to make it deliberate to reader to get the attributes that expands in the same way, but without the need to declare them explicitly as object.

答案1

得分: 1

以下是代码部分的翻译:

struct Attribute {
    file_name: &amp;&#39;static str,
    code: i32,
    companion_name: &amp;&#39;static str,
}
struct ObjAttribution {
    id: &amp;&#39;static str,
    attribute_type: Attribute,
}
impl ObjAttribution {
    const fn new(id: &amp;&#39;static str, file_name: &amp;&#39;static str, code: i32, companion_name: &amp;&#39;static str) -&gt; Self {
        ObjAttribution {
            id,
            attribute_type: Attribute {
                file_name,
                code,
                companion_name,
            },
        }
    }
}

macro_rules! x {
    ($id:ident, $x:literal, $y:literal, $z:literal) =&gt; {
        const $id: ObjAttribution = ObjAttribution::new(stringify!($id), $x, $y, $z);
    };
}

x!(USER_IO, &quot;user_info.txt&quot;, 64, &quot;user_companion.txt&quot;);
x!(USER_IO_1, &quot;user_info_1.txt&quot;, 65, &quot;user_companion_1.txt&quot;);
x!(USER_IO_2, &quot;user_info_2.txt&quot;, 66, &quot;user_companion_2.txt&quot;);
x!(USER_IO_3, &quot;user_info_3.txt&quot;, 67, &quot;user_companion_3.txt&quot;);
x!(USER_IO_4, &quot;user_info_4.txt&quot;, 68, &quot;user_companion_4.txt&quot;);
x!(USER_IO_5, &quot;user_info_5.txt&quot;, 69, &quot;user_companion_5.txt&quot;);
x!(USER_IO_6, &quot;user_info_6.txt&quot;, 70, &quot;user_companion_6.txt&quot;);
x!(USER_IO_7, &quot;user_info_7.txt&quot;, 71, &quot;user_companion_7.txt&quot;);
x!(USER_IO_8, &quot;user_info_8.txt&quot;, 72, &quot;user_companion_8.txt&quot;);

fn main() {
    println!(&quot;{} --&gt; {} --&gt; {} --&gt; {}&quot;, USER_IO_1.id, USER_IO_1.attribute_type.file_name, USER_IO_1.attribute_type.code, USER_IO_1.attribute_type.companion_name);
    println!(&quot;{} --&gt; {} --&gt; {} --&gt; {}&quot;, USER_IO_2.id, USER_IO_2.attribute_type.file_name, USER_IO_2.attribute_type.code, USER_IO_2.attribute_type.companion_name);
    println!(&quot;{} --&gt; {} --&gt; {} --&gt; {}&quot;, USER_IO_3.id, USER_IO_3.attribute_type.file_name, USER_IO_3.attribute_type.code, USER_IO_3.attribute_type.companion_name);
    println!(&quot;{} --&gt; {} --&gt; {} --&gt; {}&quot;, USER_IO_4.id, USER_IO_4.attribute_type.file_name, USER_IO_4.attribute_type.code, USER_IO_4.attribute_type.companion_name);
    println!(&quot;{} --&gt; {} --&gt; {} --&gt; {}&quot;, USER_IO_5.id, USER_IO_5.attribute_type.file_name, USER_IO_5.attribute_type.code, USER_IO_5.attribute_type.companion_name);
    println!(&quot;{} --&gt; {} --&gt; {} --&gt; {}&quot;, USER_IO_6.id, USER_IO_6.attribute_type.file_name, USER_IO_6.attribute_type.code, USER_IO_6.attribute_type.companion_name);
    println!(&quot;{} --&gt; {} --&gt; {} --&gt; {}&quot;, USER_IO_7.id, USER_IO_7.attribute_type.file_name, USER_IO_7.attribute_type.code, USER_IO_7.attribute_type.companion_name);
}

请注意,这段代码中的字符串被HTML实体编码,所以在翻译中保留了这些编码。

英文:

It's pretty simple if you can accept quoting the names:

struct Attribute {
    file_name: &amp;&#39;static str,
    code: i32,
    companion_name: &amp;&#39;static str,
}
struct ObjAttribution {
    id: &amp;&#39;static str,
    attribute_type: Attribute,
}
impl ObjAttribution {
    const fn new(id: &amp;&#39;static str, file_name: &amp;&#39;static str, code: i32, companion_name: &amp;&#39;static str) -&gt; Self {
        ObjAttribution {
            id,
            attribute_type: Attribute {
                file_name,
                code,
                companion_name,
            },
        }
    }
}

macro_rules! x {
    ($id:ident, $x:literal, $y:literal, $z:literal) =&gt; {
        const $id: ObjAttribution = ObjAttribution::new(stringify!($id), $x, $y, $z);
    };
}

x!(USER_IO, &quot;user_info.txt&quot;, 64, &quot;user_companion.txt&quot;);
x!(USER_IO_1, &quot;user_info_1.txt&quot;, 65, &quot;user_companion_1.txt&quot;);
x!(USER_IO_2, &quot;user_info_2.txt&quot;, 66, &quot;user_companion_2.txt&quot;);
x!(USER_IO_3, &quot;user_info_3.txt&quot;, 67, &quot;user_companion_3.txt&quot;);
x!(USER_IO_4, &quot;user_info_4.txt&quot;, 68, &quot;user_companion_4.txt&quot;);
x!(USER_IO_5, &quot;user_info_5.txt&quot;, 69, &quot;user_companion_5.txt&quot;);
x!(USER_IO_6, &quot;user_info_6.txt&quot;, 70, &quot;user_companion_6.txt&quot;);
x!(USER_IO_7, &quot;user_info_7.txt&quot;, 71, &quot;user_companion_7.txt&quot;);
x!(USER_IO_8, &quot;user_info_8.txt&quot;, 72, &quot;user_companion_8.txt&quot;);

fn main() {
    println!(&quot;{} --&gt; {} --&gt; {} --&gt; {}&quot;, USER_IO_1.id, USER_IO_1.attribute_type.file_name, USER_IO_1.attribute_type.code, USER_IO_1.attribute_type.companion_name);
    println!(&quot;{} --&gt; {} --&gt; {} --&gt; {}&quot;, USER_IO_2.id, USER_IO_2.attribute_type.file_name, USER_IO_2.attribute_type.code, USER_IO_2.attribute_type.companion_name);
    println!(&quot;{} --&gt; {} --&gt; {} --&gt; {}&quot;, USER_IO_3.id, USER_IO_3.attribute_type.file_name, USER_IO_3.attribute_type.code, USER_IO_3.attribute_type.companion_name);
    println!(&quot;{} --&gt; {} --&gt; {} --&gt; {}&quot;, USER_IO_4.id, USER_IO_4.attribute_type.file_name, USER_IO_4.attribute_type.code, USER_IO_4.attribute_type.companion_name);
    println!(&quot;{} --&gt; {} --&gt; {} --&gt; {}&quot;, USER_IO_5.id, USER_IO_5.attribute_type.file_name, USER_IO_5.attribute_type.code, USER_IO_5.attribute_type.companion_name);
    println!(&quot;{} --&gt; {} --&gt; {} --&gt; {}&quot;, USER_IO_6.id, USER_IO_6.attribute_type.file_name, USER_IO_6.attribute_type.code, USER_IO_6.attribute_type.companion_name);
    println!(&quot;{} --&gt; {} --&gt; {} --&gt; {}&quot;, USER_IO_7.id, USER_IO_7.attribute_type.file_name, USER_IO_7.attribute_type.code, USER_IO_7.attribute_type.companion_name);
}

playground

It's probably possible to avoid quoting the strings, but would make the macro drastically more complex.

Note: I used &amp;&#39;static str because Rust doesn't allow creating Strings (except empty ones) in constant contexts. If you want to use ObjAttribution in both const and non-const contexts, you'll probably have to switch to Cow&lt;&#39;static, str&gt;.

huangapple
  • 本文由 发表于 2023年3月10日 01:28:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/75688088.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定