il limite T: Mul
non implica che il risultato del operatore binario è anche di tipo T
. Il tipo di risultato è un tipo associato di questo tratto: Output
.
L'altro problema è che ad un certo punto nel tempo i tratti dell'operatore sono passati da pass-per-referece a pass-per-valore. Nel codice generico questo può essere un po 'un fastidio nel sedere (almeno per ora) perché questi operatori consumano i propri operandi a meno che non si richieda che i tipi siano Copy
.
Solo per completezza (nel caso non si desideri richiedere Copy
), aggiungere alcune informazioni su una possibile direzione alternativa.
Per motivi di codice generico, autori di "tipi numerici" sono invitati a fornire ulteriori non consumano implementazioni di questi tratti operatore in modo che non hai bisogno di Copy
o Clone
. Ad esempio, la libreria standard fornisce già le seguenti implementazioni:
f64 implements Mul< f64>
f64 implements Mul<&f64>
&f64 implements Mul< f64>
&f64 implements Mul<&f64>
con ogni implementazione avente f64
come Output
tipo.Ma facendo uso di questi tratti direttamente non è abbastanza:
fn cube<T>(x: &T) -> T
where for<'a> T: Mul<&'a T, Output = T>,
for<'a,'b> &'a T: Mul<&'b T, Output = T>
{
x * x * x
}
Alla fine, potremmo ottenere alcuni tratti (leggermente) più alto livello, che ridurrebbe il rumore. Ad esempio: T: Mul2
potrebbe implicare T: Mul<T> + Mul<&T>
e &T: Mul<T> + Mul<&T>
. Ma al momento di scrivere questo, il compilatore di Rust non sembra in grado di gestirlo. Almeno io non sono riuscito a compilare correttamente il seguente codice:
use std::ops::Mul;
pub trait Mul2 where
Self: Mul<Self, Output=Self>,
Self: for<'a> Mul<&'a Self, Output=Self>,
for<'a> &'a Self: Mul<Self, Output=Self>,
for<'a,'b> &'a Self: Mul<&'b Self, Output=Self> {}
impl<T> Mul2 for T where
T: Mul<T, Output=T>,
T: for<'a> Mul<&'a T, Output=T>,
for<'a> &'a T: Mul<T, Output=T>,
for<'a,'b> &'a T: Mul<&'b T, Output=T> {}
fn cube<T: Mul2>(x: &T) -> T {
x * x * x
}
fn main() {
let c = cube(&2.3);
println!("Hello, world! {}", c)
}
Penso che sia giusto dire che le cose miglioreranno in questo settore. Per ora, la capacità di implementare genericamente algoritmi numerici in Rust non è buona come vorrei.
Puoi spiegare anche (o semplicemente dare un link) la notazione "where for", non l'ho mai vista prima. –
dove clausole sono un modo più generale di vincolare i parametri generici. Sono stati introdotti tramite https://github.com/rust-lang/rfcs/blob/master/text/0135-where.md – sellibitze
La notazione 'for <'a>' è stata introdotta in RFC 387: https://github.com /rust-lang/rfcs/blob/master/text/0387-higher-ranked-trait-bounds.md. –