2 votes

Comment nommer le type d'une fonction associée en Rust ?

J'essaie d'écrire un code qui est générique pour une opération, mais qui possède également des fonctions de commodité pour les opérations les plus courantes, comme l'addition, que je veux définir pour tous les types T: Add .

Cela fonctionne bien si je définis des fonctions autonomes puisque je peux utiliser impl Trait dans la valeur de retour pour cacher le type opaque.

Cependant, si je veux définir cette fonction à l'intérieur d'un trait, je suis obligé de nommer le type de <T as Add>::add . Comment puis-je faire ?

use std::ops::Add;

struct Operation<T, F>
where
    F: Fn(T, T) -> T,
{
    arg: T,
    f: F,
}

fn addition<T>(arg: T) -> Operation<T, impl Fn(T, T) -> T>
where
    T: Add<Output = T>,
{
    Operation { arg, f: T::add }
}

trait Addable<T>
where
    T: Add<Output = T>,
{
    fn addition(self) -> Operation<T, impl Fn(T, T) -> T>;
    //fn addition(self) -> Operation<T, ???>;
}

Erreur :

error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
  --> src/main.rs:22:39
   |
22 |     fn addition(self) -> Operation<T, impl Fn(T, T) -> T>;
   |                                       ^^^^^^^^^^^^^^^^^^

4voto

kfedorov91 Points 2277

La raison impl Trait n'est pas autorisé dans la position de retour des méthodes de trait est parce qu'il peut y avoir plusieurs implémentations de la méthode, alors que impl Trait n'est valable que s'il existe une seule implémentation de la fonction ou de la méthode.

Une option serait d'utiliser une fermeture d'objet de trait encadrée :

trait Addable<T>
where
    T: Add<Output = T>,
{
    fn addition(self) -> Operation<T, Box<dyn Fn(T, T) -> T>>;
}

Cependant, comme il semble peu probable que la fermeture ait besoin de capturer des variables de son environnement, vous pouvez utiliser un simple pointeur de fonction à la place. Cela vous évite une allocation inutile du tas. Voici un exemple simple i32 exemple en utilisant un simple pointeur de fonction dans le type de retour de la méthode trait :

trait Addable<T>
where
    T: Add<Output = T>,
{
    fn addition(self) -> Operation<T, fn(T, T) -> T>;
}

struct SomeType {
    arg: i32,
}

impl Addable<i32> for SomeType {
    fn addition(self) -> Operation<i32, fn(i32, i32) -> i32> {
        Operation {
            arg: self.arg,
            f: i32::add,
        }
    }
}

Voici un exemple générique utilisant un pointeur de fonction simple dans le type de retour de la méthode trait :

trait Addable<T>
where
    T: Add<Output = T>,
{
    fn addition(self) -> Operation<T, fn(T, T) -> T>;
}

struct SomeType<T> {
    arg: T,
}

impl<T> Addable<T> for SomeType<T>
    where T: Add + Add<Output = T>
{
    fn addition(self) -> Operation<T, fn(T, T) -> T> {
        Operation {
            arg: self.arg,
            f: T::add,
        }
    }
}

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