2 votes

Comment puis-je renvoyer l'un des multiples types qui implémentent un trait non sécurisé pour les objets ?

Je veux une fonction qui renvoie plusieurs types de Range (par exemple, Range, RangeFrom, RangeTo). Mon objectif est de vérifier si les valeurs se trouvent dans des plages dont nous ne savons pas à l'avance si elles sont ouvertes ou fermées.

J'ai essayé de le faire en spécifiant le type de retour de RangeBounds. Malheureusement, étant donné que .contains est générique, je ne pense pas que cela soit possible.

Y a-t-il une autre solution? Ou devrais-je simplement passer (Option, Option) et vérifier les valeurs manuellement?

Cette question est plus large que simplement expliquer cette erreur spécifique - j'essaie de trouver s'il y a un autre moyen d'atteindre l'objectif. Je veux utiliser les outils de la bibliothèque standard Range plutôt qu'une implémentation personnalisée.

use std::ops::{Range, RangeBounds};

fn range(start: Option, end: Option) -> dyn RangeBounds {
    match (start, end) {
        (Some(s), Some(e)) => Range { s, e },
        // other options here
        _ => panic!(),
    }
}

Causes:

error[E0038]: le trait `std::ops::RangeBounds` ne peut pas être transformé en objet
 --> src/lib.rs:3:1
  |
3 | fn range(start: Option, end: Option) -> dyn RangeBounds {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ le trait `std::ops::RangeBounds` ne peut pas être transformé en objet
  |
  = note: la méthode `contains` a des paramètres de type générique

Une autre approche qui ne fonctionne pas:

use std::ops::{Range, RangeBounds, RangeFrom, RangeTo};

fn range(start: Option, end: Option) -> impl RangeBounds {
    match (start, end) {
        (Some(s), Some(e)) => Range { start: s, end: e },
        (Some(s), None) => RangeFrom { start: s },
        // other options here
        _ => panic!(),
    }
}

error[E0308]: les bras du match ont des types incompatibles
  --> src/main.rs:18:28
   |
16 | /     match (start, end) {
17 | |         (Some(s), Some(e)) => Range { start: s, end: e  },
   | |                               --------------------------- cela est trouvé comme étant de type `std::ops::Range`
18 | |         (Some(s), None) => RangeFrom { start: s },
   | |                            ^^^^^^^^^^^^^^^^^^^^^^ struct attendu `std::ops::Range`, struct trouvé `std::ops::RangeFrom`
19 | |         // other options here
20 | |         _ => panic!(),
21 | |     }
   | |_____- les bras du `match` ont des types incompatibles

0 votes

Merci pour les modifications @Shepmaster

2 votes

Votre deuxième exemple ne fonctionne pas car impl Trait en tant que type de retour ne peut pas être utilisé pour plusieurs types conditionnels.

4voto

Shepmaster Points 1732

Vous ne le pouvez pas. Vous ne pouvez pas retourner un objet de trait pour les traits qui ne sont pas sûrs pour les objets. Cela est déjà expliqué en détail:

À la place, définissez votre propre trait sûr pour les objets et implémentez-le en fonction de celui qui n'est pas sûr pour les objets:

use std::ops::{Range, RangeBounds};

trait MyBounds {
    fn contains(&self, v: &isize) -> bool;
}

impl MyBounds for T
where
    T: RangeBounds,
{
    fn contains(&self, v: &isize) -> bool {
        RangeBounds::contains(self, v)
    }
}

fn range(start: Option, end: Option) -> Box {
    match (start, end) {
        (Some(start), Some(end)) => Box::new(Range { start, end }),
        // autres options ici
        _ => panic!(),
    }
}

Voir aussi:

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