3 votes

Comment définir un pointeur vers une fonction de trait en Rust ?

Je m'excuse si ma question a déjà reçu une réponse ou se trouve quelque part dans la documentation, mais je n'ai pas réussi à trouver la réponse. Supposons que j'ai le code suivant :

trait Saluter {
    fn hello(&self);
    fn bye(&self);
}

struct A {}
struct B {}

impl Saluter for A {
    fn hello(&self) {
        println!("Hello A!");
    }

    fn bye(&self) {
        println!("Bye A!");
    }
}

impl Saluter for B {
    fn hello(&self) {
        println!("Hello B!");
    }

    fn bye(&self) {
        println!("Bye B!");
    }
}

pub struct Foo {
    saluter: Box<dyn Saluter>,
    salute: fn (&dyn Saluter),
}

fn main() {
    let x = Foo {saluter: Box::new(A{}), salute: Saluter::hello};
    let y = Foo {saluter: Box::new(B{}), salute: Saluter::bye};
    (x.salute)(x.saluter.borrow()); //Should print "Hello A!"
    (y.salute)(y.saluter.borrow()); //Should print "Hello B!"
}

En fait, j'essaie de manipuler indépendamment l'appelant et la méthode appelée. Cependant, j'obtiens l'erreur de compilation suivante :

let x = Foo {saluter: Box::new(A{}), salute: Saluter::hello};
   |                                                  ^^^^^^^^^^^^^^ one type is more general than the other
   |
   = note: expected fn pointer `for<'r> fn(&'r (dyn Saluter + 'r))`
              found fn pointer `for<'r> fn(&'r dyn Saluter)`

La même erreur s'applique pour y évidemment. Je n'ai commencé que récemment à apprendre Rust, donc je ne suis pas du tout à l'aise avec les paramètres de durée de vie Rust, mais il me semble qu'il se plaint de cela, bien que je n'ai pas pu trouver ce que (dyn Salute + 'r) signifierait exactement.

Y a-t-il un moyen d'obtenir ce que je veux ou est-ce simplement impossible en Rust ? En C++, je pourrais le faire facilement avec des pointeurs vers la classe de base, mais j'ai du mal à trouver comment le faire en Rust.

Merci pour votre aide !

0voto

Daniel Sanchez Points 2626

Vous utilisez un type générique lié par Saluter dans votre Foo struct :

pub struct Foo<T> where T: Saluter {
    saluter: Box<T>,
    salute: fn (&T),
}

Terrain de jeux

0voto

Kevin Reid Points 8806

J'ai réussi à faire compiler votre code en limitant simplement le type de pointeur de fonction :

pub struct Foo {
    saluter: Box<dyn Saluter>,
    salute: fn (&(dyn Saluter + 'static)),
}

Ce que ce supplément + 'static La contrainte signifie que la salute pointeur de fonction stocké dans Foo ne peut être utilisé qu'avec types de mise en œuvre Saluter qui n'ont pas de durée de vie limitée - au sens large, "ne contiennent pas de références non statiques". Autrement dit, si vous aviez

struct B<'x> { ... }
impl<'x> Saluter for B<'x> {}

alors la fonction ne serait pas utilisable. Cependant, il s'agit d'un cas peu fréquent.

Malheureusement, je ne suis pas sûr de savoir pourquoi le pointeur de fonction Saluter::hello ne peut pas être le type entièrement général qui était impliqué par votre code original,

    salute: for<'a> fn (&'a (dyn Saluter + 'a)),

donc je ne peux pas en donner une explication complète.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X