c'è un modo per farlo senza estrarre i loro valori "interni" ogni volta con pattern matching, e senza l'attuazione del Add, Sub, .. . Tratti e operatori di sovraccarico?
No, l'unico modo è di implementare manualmente i tratti. Ruggine non ha un valore equivalente a su tipi di wrapper per implementare automaticamente qualsiasi tipo di classe/tratto che il tipo avvolto implementa (e con l'attuale configurazione di Rust #[derive]
come una semplice trasformazione AST, implementandola come Haskell è . essenzialmente impossibile)
per abbreviare il processo, è possibile utilizzare una macro:
use std::ops::{Add, Sub};
macro_rules! obvious_impl {
(impl $trait_: ident for $type_: ident { fn $method: ident }) => {
impl $trait_<$type_> for $type_ {
type Output = $type_;
fn $method(self, $type_(b): $type_) -> $type_ {
let $type_(a) = self;
$type_(a.$method(&b))
}
}
}
}
#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Debug)]
pub struct Centimeters(i32);
obvious_impl! { impl Add for Centimeters { fn add } }
obvious_impl! { impl Sub for Centimeters { fn sub } }
#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Debug)]
pub struct Inches(i32);
obvious_impl! { impl Add for Inches { fn add } }
obvious_impl! { impl Sub for Inches { fn sub } }
fn main() {
let a = Centimeters(100);
let b = Centimeters(200);
let c = Inches(10);
let d = Inches(20);
println!("{:?} {:?}", a + b, c + d); // Centimeters(300) Inches(30)
// error:
// a + c;
}
playpen
ho emulato il normale impl
sintassi nella macro per rendere evidente ciò che sta accadendo ju st osservando la macro invocazione (es. riducendo la necessità di guardare alla definizione della macro), e anche per mantenere la naturalezza della ricerca di Rust: se stai cercando tratti su Centimeters
, basta grep per for Centimeters
e troverai queste invocazioni di macro insieme ai normali impl
s.
Se si accede il contenuto del tipo Centimeters
molto, si potrebbe considerare l'utilizzo di una struttura adeguata con un campo per definire l'involucro:
struct Centimeters { amt: i32 }
Questo permette di scrivere self.amt
invece di dover fare la corrispondenza del modello. Puoi anche definire una funzione come fn cm(x: i32) -> Centimeters { Centimeters { amt: x } }
, chiamata come cm(100)
, per evitare la verbosità di costruire una struttura completa.
È inoltre possibile accedere ai valori interni di una struttura di tupla utilizzando la sintassi .0
, .1
.
Ero quasi sicuro che i macro fossero la strada da percorrere, ma non li ho ancora padroneggiati :) Se si suggeriscono le strutture appropriate, quale è esattamente il caso d'uso per le strutture one-field? –
@ anonymous_user_13 Intendi una struttura tupla a un campo? La sintassi di costruzione predefinita è più gradevole e il fatto di non dover pensare a un nome per il campo sono gli unici vantaggi a cui riesco a pensare. – huon