英文:
#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 inKruskal
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>
> But I'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(/* ... */) -> Self {
/* ... */
Self {
u: UnionFind::new(0),
}
}
}
}
use kruskal::Kruskal;
This way, you'll always get UnionFind with your code, but nothing else will change.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论