Здравейте!
Моля за малко помощ/съвети. :)
Играя си с IR на език за програмиране в Rust структури и се опитвам да задоволя borrow checker-а. Имам следния набор от структури, с ненужните части изтрити за прегледност:
struct Runtime<'a> {
functions: HashMap<String, Function<'a>>
}
struct Function<'a> {
scope: Scope<'a>,
code: Block<'a>
}
struct Scope<'a> {
runtime: &'a Runtime<'a>,
vars: HashMap<String, Variable>
}
struct Variable {
name: String
// + other metadata
}
pub enum Instruction<'a> {
// Literal(ConstValue),
VariableRef(&'a Variable),
// Call(Call<'a>),
Block(Block<'a>)
}
struct Block<'a> {
code: Vec<Instruction<'a>>
}
impl<'a> Function<'a> {
pub fn build(ast: &'a parser::MethodDefAST, runtime: &'a Runtime<'a>) -> Function<'a> {
// Тук се проявяват проблемите
}
}
impl<'a> Instruction<'a> {
pub fn build(ast: &'a AST, scope: &'a Scope<'a>) -> Instruction<'a> {
// Това конструира Instruction обект, евентуално реферирайки променливи от scope-а
}
}
Идеята е следната:
-
Runtime
държи всичко - трябва да е owner на всичко по транзитивност. -
Function
описва функция, съответно имаscope
за локални променливи вътре + код, който трябва да се изпълни. -
Scope
е owner на променливите и му трябва референция къмRuntime
, за да може да търси функции. -
Variable
не е само име, има други неща вътре, съответно не мога да го приравня къмString
. Идеята е ако някъде се иска променлива, то тя да се специфицира с референцията къмVariable
, не само с име. Това е така, защото името може да не е уникално и зависи от scope-а. -
Instruction
е нещо, което може да реферира променливи.
Проблемите са основно с цикличните зависимости:
-
Runtime
държи функции, но функциите иматscope
, който реферираRuntime
. - Функцията държи
scope
, но и код, който може да реферира променливи от тозиscope
. Като резултат, няма как да конструирамFunction
обект, защото трябва да вземаscope
от вече конструирания, за да го реферирам от code.
Може ли съвет как да променя структурите, така че borrow checker-а да е доволен?
Четох, че може да се използва Rc<RefCell<T>>
в подобни ситуации:
- Добра идея ли е това в случая?
- Губя ли compile-time проверките, че докато имам Function ще е жив и Runtime-а? Тоест, мога ли да запазя текущите lifetime връзки, или някоя от тях поражда проблемите?
- Навсякъде ли е нужно да минава през
Rc<RefCell<T>>
или има начин да се реферират по този начин само при връзките отдолу-нагоре? - Ако направя
Scope
иVariable
RC-та мисля, че няма да има циклични зависимости между RC обектите (тоест няма да тече памет). Има ли нещо, което пропускам?
Има ли нещо по-добро от Rc<RefCell<T>>
в случая?
Благодаря предварително :)