#define 和 #ifdef 宏在 Rust 中的使用方式是:

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

#define and #ifdef macro in Rust

问题

#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
struct UnionFind {
    /* ... */
}
impl UnionFind {
    /* ... */
}

#[derive(Debug, Clone)]
struct Kruskal {
    u: UnionFind,
    /* ... */
}
impl Kruskal {
    fn new(/* ... */) -> Self {
        /* ... */
        Self {
            u: UnionFind::new(0),
        }
    }
}
为了解决这个问题,我需要确保在插入 `Kruskal` 代码时也会自动插入 `UnionFind` 代码。如果 `UnionFind` 未导入,则编译器将会报错,并显示友好的错误消息(例如:`UnionFind 未导入。请在 Vim 中执行 :I unionfind。`)。

请注意:

- 在竞技程序环境中不能使用模块系统(只能提交单个源文件)。

- 我不想为了可维护性而在 `Kruskal` 片段中复制 `UnionFind` 代码。

- 在我的片段插入器(即 `:I` 命令的后端)中实现依赖管理系统是最后的选择。
英文:

Is it possible to rewrite this C++ code into Rust?

#define is_unionfind_imported
class UnionFind {
};

class Kruskal {
#ifndef is_unionfind_imported
    #error "UnionFind not imported"
#endif
    UnionFind u;
};

int main() {
}

Why, in the first place?

I often do competitive programming in Rust. In competitive programming, users usually register the source codes of frequently used data structures as snippets.

For example, in my case, this code is inserted from ~/snippets/union_find.rs when I execute :I unionfind command in Vim:

#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
struct UnionFind {
    /* ... */
}
impl UnionFind {
    /* ... */
}

Also, when I execute :I kruskal in Vim, this code is inserted from ~/snippets/kruskal_method.rs:

#[derive(Debug, Clone)]
struct Kruskal {
    u: UnionFind,
    /* ... */
}
impl Kruskal {
    fn new(/* ... */) -> Self {
        /* ... */
        Self {
            u: UnionFind::new(0),
        }
    }
}

The problem is Kruskal depends on UnionFind. If I manually execute :I UnionFind and :I Kruskal, there is no problem, but I often forget to first import UnionFind. Then the compiler says

error[E0412]: cannot find type `UnionFind` in this scope

but I'd like to make this error message more user-friendly (e.g. UnionFind is not imported. Execute :I unionfind in Vim.).

And please note

  • Module system cannot be used in competitive programming environment. (Only a single source file can be submitted.)

  • I don't want to replicate UnionFind code in Kruskal snippet for maintainability.

  • Implementing a dependency management system in my snippet inserter (i.e. the backend of :I command) is the last resort.

答案1

得分: 1

// 我已经炮制了一个临时解决方案。

mod placeholders {
    pub struct UnionFind;
    pub const UNION_FIND_IMPORTED: bool = false;
}

use placeholders::*;

// 开始片段
struct Kruskal {
    u: UnionFind,
}
const _: () = if !UNION_FIND_IMPORTED {
    panic!("UnionFind没有被导入。在Vim中执行:I unionfind。");
};
// 结束片段

// 开始片段
// struct UnionFind;
// const UNION_FIND_IMPORTED: bool = true;
// 结束片段

fn main() {
    println!("你好");
}
英文:

I've cooked up a hacky solution.

#![allow(unused)]

mod placeholders {
    pub struct UnionFind;
    pub const UNION_FIND_IMPORTED: bool = false;
}

use placeholders::*;

// Start snippet
struct Kruskal {
    u: UnionFind,
}
const _: () = if !UNION_FIND_IMPORTED {
    panic!("UnionFind is not imported. Execute :I unionfind in Vim.");
};
// End snippet

// Start snippet
// struct UnionFind;
// const UNION_FIND_IMPORTED: bool = true;
// End snippet

fn main() {
    println!("hello");
}

The way this works is that when the UnionFind snippet is not present, it is pulled from the glob import. This means UnionFind is always present. In order to check if it's the right one, the constant UNION_FIND_IMPORTED is present next to both UnionFind structs. This is then compile-time evaluated with const _: (), which will compile-panic when the import constant is false.

Pros:

  • Custom error message
  • Single file
  • No CLI args needed

Cons:

  • Requires you to have a placeholder module with all your types and the same implemented methods and traits as your real types so that the compiler doesn't stop before const evaluation
  • Extra constants

答案2

得分: 0

> 但我想让这个错误消息更加用户友好(例如:UnionFind 未被导入。在 Vim 中执行 :I unionfind)。

在 Rust 中直接更改错误消息是不可能的。

考虑到你使用代码片段,你尝试将 UnionFind 添加到你的 Kruskal 代码片段中了吗?

你也可以在一个源文件中使用模块。

例如,你可以将 `~/snippets/kruskal_method.rs` 替换为:

```Rust
mod kruskal {
    #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
    struct UnionFind {
        /* ... */
    }
    impl UnionFind {
        /* ... */
    }

    #[derive(Debug, Clone)]
    pub struct Kruskal {
        u: UnionFind,
        /* ... */
    }
    impl Kruskal {
        pub fn new(/* ... */) -> Self {
            /* ... */
            Self {
                u: UnionFind::new(0),
            }
        }
    }
}

use kruskal::Kruskal;

这样,你的代码将始终包含 UnionFind,但其他什么都不会改变。


<details>
<summary>英文:</summary>

&gt; But I&#39;d like to make this error message more user-friendly (e.g. UnionFind is not imported. Execute :I unionfind in Vim.).

Changing error messages is not directly possible with Rust.

Considering you work with snippets, have you tried adding UnionFind into your Kruskal snippet?

You can also use modules within a source file.


For example, you could replace ` ~/snippets/kruskal_method.rs` with this:

```Rust
mod kruskal {
    #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
    struct UnionFind {
        /* ... */
    }
    impl UnionFind {
        /* ... */
    }

    #[derive(Debug, Clone)]
    pub struct Kruskal {
        u: UnionFind,
        /* ... */
    }
    impl Kruskal {
        pub fn new(/* ... */) -&gt; Self {
            /* ... */
            Self {
                u: UnionFind::new(0),
            }
        }
    }
}

use kruskal::Kruskal;

This way, you'll always get UnionFind with your code, but nothing else will change.

huangapple
  • 本文由 发表于 2023年6月18日 19:21:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76500276.html
匿名

发表评论

匿名网友

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

确定