Immutable et mutable "borrow" ensemble

Le problème exposé dans ce sujet a été résolu.

Bonjour (bonsoir plutôt :p ),

Je me re-suis mis à apprendre Rust depuis le début de la semaine et pour m'excercer je suis en train de faire un interpréteur BF.

Les instructions '<', '>', '+', '-', et '.' sont déjà implementé, donc pour tester j'ai voulu coder la fonction interpret:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
pub fn interpret(&mut self) -> Result<(), BFError> {
    for c in self.prg.chars() {
        match c {
            '>' => try!(self.move_right()),
            '<' => try!(self.move_left()),
            '+' => try!(self.increment()),
            '-' => try!(self.decrement()),
            '.' => try!(self.putchar()),
            /*',' =>,
            '[' =>,
            ']' =>,*/
            _   => {}
        }
    }
    Ok(())
}

Mais j'ai une erreur:

1
2
3
4
5
6
7
8
9
error: cannot borrow `*self` as mutable because `self.prg` is also borrowed as immutable
54  |>         for c in self.prg.chars() {
    |>                  -------- immutable borrow occurs here
55  |>             match c {
56  |>                 '>' => try!(self.move_right()),
    |>                             ^^^^ mutable borrow occurs here
...
66  |>         }
    |>         - immutable borrow ends here

J'ai beau chercher, je ne trouve pas comment faire pour éviter ça, hormis un truc crade je trouve, qui est de rajouter .collect::<Vec<char>>() à self.prg.chars()

Est-ce que vous auriez une idée ?

Merci,
Ardakaniz

P.S: Autre petite question, comment on fait pour créer des méthodes privées ? Parce que j'aimerais bien que mes fonctions increment, decrement, etc… le soit pour ne pas pouvoir les appeler de l'extérieur. Merci encore :)

Ton erreur viens du fait que rustc ne sais pas que tu ne touche pas à self.prg dans increment et cie. Du coup, pour éviter les problèmes, il refuse d’appeler ces fonctions. Comme solutions, je vois :

  • inliner à la main les fonctions increment, … dans le match;
  • cloner self.prg (avec self.prg.chars().cloned() ou avec collect);

Il y a sans doutes d'autres solutions, mais ça dépends du reste de ton code!

P.S: Autre petite question, comment on fait pour créer des méthodes privées ? Parce que j'aimerais bien que mes fonctions increment, decrement, etc… le soit pour ne pas pouvoir les appeler de l'extérieur.

Elles le sont par défault ! Elles ne sont publiques que si tu les déclare avec pub fn foo() au lieu de fn foo().

+1 -0

cloner self.prg (avec self.prg.chars().cloned() ou avec collect);

Pour avoir déjà essayé, ça ne marche pas : clone emprunte la variable en non-mutable et génère la même erreur.

De ce que je comprends de ton code, tu as une structure, qui contient le code source du programme dans son champ prg, et des infos sur l’état du programme dans un ou plusieurs autres champs non nommés ici. Et tes méthodes increment, decrement, etc. agissent sur ces champs non-nommés.

La solution, c’est que tu regroupes les infos sur l’état du programme dans une structure State, qui sera le champ state de ta grosse structure. Et increment, decrement, etc. seront des méthodes de State. De cette manière, tu feras self.prg.chars() et self.state.increment(), et ton problème devrait être résolu. :)

+1 -0

inliner à la main les fonctions increment, … dans le match;

Luthaf

J'avais commencé par faire ça puis j'ai vu le message de Dominus :D Du coup, sa solution fonctionne aussi et je la trouve plus pratique que d'inliner à la main.

Elles le sont par défault ! Elles ne sont publiques que si tu les déclare avec pub fn foo() au lieu de fn foo().

Luthaf

C'est bien ce que je pensais pourtant sur "play.ryst-lang.org" (je n'ai pas rustc sous la main), on peut quand même y accéder. J'ai peut être loupé quelque chose au niveau des struct ?

C'est bien ce que je pensais pourtant sur "play.ryst-lang.org" (je n'ai pas rustc sous la main), on peut quand même y accéder. J'ai peut être loupé quelque chose au niveau des struct ?

C'est normal, la visibilité est définie au niveau d'un module. Cet example marche.

Merci, j'avais pas encore vu cette notion.

Je vais un peu faire du HS maintenant mais, j'ai mon programme fini qui fonctionne parfaitement ! … sauf avec les programmes qui utilises trop de boucles, ça me donne :
thread '<main>' has overflowed its stack
error: Process didn't exit successfully: `target\debug\bf_interpreter.exe test.bf` (exit code: 3221225725)

Ce qui m'empêche donc de tester la fractale de mandlebrot :/ C'est dû à des appels récursifs de fonction…

Il y aurait un moyen de résoudre ce problème sans que j'ai à refaire l'interpréteur d'une autre façon ?

cloner self.prg (avec self.prg.chars().cloned() ou avec collect);

Pour avoir déjà essayé, ça ne marche pas : clone emprunte la variable en non-mutable et génère la même erreur.

Heu, non: https://is.gd/kojkvq. Par contre Iterator::cloned() ne fonctionne en effet pas, parce que chars en renvoie pas un itérateur sur des références (c'est ça de ne pas tester ses exemples aussi …)

Ce qui m'empêche donc de tester la fractale de mandlebrot :/ C'est dû à des appels récursifs de fonction…

Tu peut changer la taille de ta pile (voir ulimit sous Linux). En général, on préférera des boucles for/while en Rust plutôt que des appels récursifs de fonctions.

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte