[Rust] Surcharge d'opérateur et génériques

Pourquoi je peux pas additionner deux variables nodidju

a marqué ce sujet comme résolu.

Salut,

Je m’amuse un peu avec Rust et je recontre actuellement le problème suivant. J’utilise la crate polynomial (https://docs.rs/polynomial), et j’essaie de soustraire deux variables dans une fonction.

A force de galères (je ne comprenais pas pourquoi je devais restreindre T), j’arrive à ce code

use std::ops::Sub;
use polynomial::Polynomial;
use num_traits::Zero;

fn create_zero<T>(a: &Polynomial<T>) -> Polynomial<T>
where T: Zero + Clone + Sub<Output = T> {
    let b = a - a;
    return b;
}

Le truc qui m’emmerde c’est que je suis obligé d’importer Sub et surtout Zero, notamment parce que ça m’oblige à déclarer num_traits dans mon fichier cargo. Aussi ça me fait un peu chier de redéclarer les restrictions de T qui sont déjà présentes dans la bibliothèque.

Je me demande donc si il y a plus simple de faire, ou si c’est une limitation de la bibliothèque (et si c’est une limitation de la bib, comment aurait-elle dû être implémentée ?).

Merci !

Salut,

C’est une restriction du système de type de Rust, en fait. Si tu veux être générique sur T, il faut être explicite sur ce que T implémente pour pouvoir appeler les méthodes correspondantes.

polynomial pourrait faire beaucoup mieux en terme d’ergonomie en re-exportant num_traits (pour ne pas avoir à déclarer la dépendance toi-même), et en ayant un prelude qui expose les traits qui vont bien pour n’avoir qu’à faire use polynomial::prelude::* côté client.


PS: j’imagine que ton code est juste pour le test, mais comme Polynomial<T: Clone+Zero> implémente Zero, tu peux simplement utiliser Zero::zero() pour créer un Polynomial<T> nul.

+2 -0

Ok je vois, j’avoue que c’est assez relou vu la multitude de traits qui sont utilisés dans tous les sens, quand je vois ce que je dois avoir comme contrainte sur T dès que j’utilise plusieurs méthodes de polynômes dans la fonction…

PS: j’imagine que ton code est juste pour le test, mais comme Polynomial<T: Clone+Zero> implémente Zero, tu peux simplement utiliser Zero::zero() pour créer un Polynomial<T> nul.

Oui bien sûr :D j’essayais juste d’avoir un code minimal qui reproduisait mon problème.

Même sans Polynomial, tu as le même problème lorsque tu essayes d’écrire du code générique sur les nombres (f32, f64, u32…). C’est objectivement un truc qui peut être assez pénible (laisser le compilo faire le taf à coup de cargo fix et s’aider du LSP limite les problèmes). Cela dit en pratique, est-ce que tu as vraiment besoin d’être générique sur le type numérique ? Je pense que le cas d’usage typique, c’est de manipuler directement des Polynomial<f64> plutôt que de rester générique.

+1 -0

Note qu’une option un peu moins verbeuse (mais moins générique en contre-partie) est de prendre un T qui implémente un/des super-traits de num_traits qui couvrent la plupart des autres traits. Num par exemple.

Cela dit, je pense que c’est un peu un piège dans lequel il est facile de tomber d’écrire un code beaucoup plus générique que ce dont tu as besoin. C’est d’autant plus vrai en calcul numérique où il y a des différences assez fondamentales entre les différents types numériques et où on a vite fait de reposer implicitement sur certains invariants.

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