2016-12-12 1 views
1

Je construis un évaluateur d'expressions paresseux like Python's en utilisant un plugin de compilateur.Conception de structures de données pour un évaluateur paresseux enfant-premier qui imprime la procédure

Je veux imprimer un journal comme:

assert (left == vec![1, 2, 3, 4]) 
assert (vec![1, 2, 3, 4] == vec![1, 2, 3, 4]); 

et essayé:

// crate rt 
pub struct Expr<T, F: FnMut() -> T> { 
    // I noticed that this must be changed to fn with format!() call, to 
    // support updating child. 
    src: &'static str, // holds value 
} 
pub trait EvalTo: Display { 
    /// Type of expression 
    type Type; 

    /// Returns Some(val) when done 
    /// Accepts &mut self as it might be called many time. 
    fn eval_one_level(&mut self) -> Some<T>; 
} 

impl<T, F> EvalTo for Expr<T, F> { 
    type Type = T; 
} 
/// Prints source before evaluation, (it must be changed) 
/// and value after evaluation. 
impl<T, F> Display for Expr<T, F> {} 

avec le plugin compilateur pour les créer sur la compilation. Mais quand je fais

let left = vec![1, 2, 3, 4]; 
lazy_expr!(left == vec![1, 2, 3, 4]); 

Il se développe pour

::rt::binary({ 
    ::rt::Expr::wrap(::rt::Source{ expr: "left" }, || Some(left)) 
}, { 
    ::rt::Expr::wrap(::rt::Source{ expr: "vec!(1, 2, 3, 4)" }, 
    || vec![1, 2, 3, 4]) 
}).eq() 

et le compilateur ne l'aime pas. Il est dit cannot move out of captured outer variable in an `FnMut` closure.

Je ne peux donc pas utiliser FnMut, mais il doit être appelé plusieurs fois et doit pouvoir modifier l'expression enfant.

Existe-t-il une structure de données permettant de capturer des variables locales, mais pouvant être appelée plusieurs fois avec &mut self? Dois-je utiliser FnOnce(&mut Context)?

+0

Veuillez générer un [MCVE]. Il est très peu probable que quelqu'un va également créer un plugin de compilation juste pour essayer de reproduire votre erreur. Idéalement, faites quelque chose qui peut [courir sur le terrain de jeu] (https://play.rust-lang.org/). Encore mieux, [passez en revue les ** 7 autres questions avec le même message d'erreur **] (http://stackoverflow.com/search?q=cannot+move+out+of+captured+outer+variable+in+an+ FnMut + closure + est% 3Aq) * avant * demande. Ensuite, expliquez pourquoi * cette question * est différente de * ces questions *. – Shepmaster

+0

J'ai décidé de faire quelque chose comme http://pybites.blogspot.kr/2011/07/behind-scenes-of-pytests-new-assertion.html parce que je ne peux pas représenter ast avec générique et cette question devient inutile pour moi . – kdy

+0

@Shepmaster Ceci est une question sur la conception, et ces questions portent sur l'utilisation de FnMut. Je n'essaie pas de faire passer la valeur à la fermeture. Au lieu de cela, je voulais faire quelque chose comme permettre à la fois FnOnce et FnMut. Et j'ai trouvé que cela peut être fait via [futures-rs] (http://alexcrichton.com/futures-rs/futures/index.html) – kdy

Répondre

0

Je n'en ai plus besoin, parce que j'ai utilisé un autre apporach. Mais pour être complet, vous pouvez définir un trait avec (&mut self) et utiliser [std::mem::replace] [] pour obtenir la valeur possédée, et Option a une méthode auxiliaire nommée.

Pour qui veut construire un moteur évaluable paresseux avec un plugin de compilateur, did some more on compile time.

Il appelle

fn capture<T :?Sized>(&mut self, expr: &'static str, val: &T) 

de code généré comme

ctx.capture("f()", &_var_of_expr) 

si le contexte peut écrire l'expression et de la valeur avec elle.