Можно ли переписать этот код C++ на Rust?
#define is_unionfind_imported
class UnionFind {
};
class Kruskal {
#ifndef is_unionfind_imported
#error "UnionFind not imported"
#endif
UnionFind u;
};
int main() {
}
Я часто занимаюсь соревновательным программированием на Rust. В соревновательном программировании пользователи обычно регистрируют исходные коды часто используемых структур данных в виде сниппетов.
Например, в моем случае этот код вставляется из ~/snippets/union_find.rs, когда я выполняю команду :I unionfind в Vim:
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
struct UnionFind {
/* ... */
}
impl UnionFind {
/* ... */
}
Кроме того, когда я запускаю :I kruskal в Vim, этот код вставляется из ~/snippets/kruskal_method.rs:
#[derive(Debug, Clone)]
struct Kruskal {
u: UnionFind,
/* ... */
}
impl Kruskal {
fn new(/* ... */) -> Self {
/* ... */
Self {
u: UnionFind::new(0),
}
}
}
Проблема в том, что Kruskal зависит от UnionFind. Если я вручную запускаю :I UnionFind и :I Kruskal, проблем нет, но я часто забываю сначала импортировать UnionFind. Затем компилятор говорит
error[E0412]: cannot find type `UnionFind` in this scope
но я хотел бы сделать это сообщение об ошибке более удобным для пользователя (например, UnionFind is not imported. Execute :I unionfind in Vim.).
И обратите внимание
Модульная система не может использоваться в конкурентной среде программирования. (Можно отправить только один исходный файл.)
Я не хочу копировать UnionFind код в Kruskal фрагменте для удобства сопровождения.
Внедрение системы управления зависимостями в моем средстве вставки сниппетов (то есть в бэкенде команды :I) — это крайняя мера.

Но я хотел бы сделать это сообщение об ошибке более удобным для пользователя (например, UnionFind не импортируется. Выполните: I unionfind в Vim.).
Изменение сообщений об ошибках невозможно напрямую в Rust.
Учитывая, что вы работаете с сниппетами, пробовали ли вы добавить UnionFind в свой сниппет Kruskal?
Вы также можете использовать модули в исходном файле.
Например, вы можете заменить ~/snippets/kruskal_method.rs на это:
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 со своим кодом, но больше ничего не изменится.
Извините, если мое намерение было двусмысленным, но ОП говорит, что я не хочу копировать код UnionFind во фрагменте Kruskal для удобства обслуживания. Я имел в виду, что не хочу встраивать UnionFind в Kruskal.
Прошу прощения, я пропустил это в вашем посте. В таком случае, я не думаю, что вашу проблему можно решить, вам придется полагаться на сообщения об ошибках Rust. Возможно, вы все еще можете использовать блоки mod {} и операторы использования, но я не проверял, какое сообщение об ошибке будет возвращено.
Я придумал хакерское решение.
#![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");
}
Это работает следующим образом: когда фрагмент UnionFind отсутствует, он извлекается из импорта glob. Это означает, что UnionFind присутствует всегда. Чтобы проверить, правильный ли он, константа UNION_FIND_IMPORTED присутствует рядом с обеими UnionFind структурами. Затем это время компиляции оценивается с помощью const _: (), что вызывает панику компиляции, когда константа импорта имеет значение false.
Плюсы:
Минусы:
Спасибо. Я думаю, что это соответствует моей потребности, хотя афера требует, чтобы у вас был модуль-заполнитель со всеми вашими типами и теми же реализованными методами и чертами, что и ваши настоящие типы, ну... может быть, слишком тяжело использовать в реальности. Кстати, во втором фрагменте, может быть, pub лишнее?
@ynn Да, паб был ошибкой копирования и вставки. Хотя особо ни на что не влияет.
В Rust есть условная компиляция, основанная на параметрах конфигурации, но, насколько мне известно, их нельзя установить из исходного кода, только как флаги для
rustcили вCargo.toml.