In Rust, tuple structs with only one field can be created like the following:
struct Centimeters(i32);
I want to do basic arithmetic with Centimeters
without extracting their "inner" values every time with pattern matching, and without implementing the Add
, Sub
, ... traits and overloading operators.
What I want to do is:
let a = Centimeters(100);
let b = Centimeters(200);
assert_eq!(a + a, b);
No, the only way is to implement the traits manually. Rust doesn't have an equivalent to the Haskell's GHC extension
GeneralizedNewtypeDeriving
which allowsderiving
on wrapper types to automatically implement any type class/trait that the wrapped type implements (and with the current set-up of Rust's#[derive]
as a simple AST transformation, implementing it like Haskell is essentially impossible.)To abbreviate the process, you could use a macro:
playpen
I emulated the normal
impl
syntax in the macro to make it obvious what is happening just by looking at the macro invocation (i.e. reducing the need to look at the macro definition), and also to maintain Rust's natural searchability: if you're looking for traits onCentimeters
just grep forfor Centimeters
and you'll find these macro invocations along with the normalimpl
s.If you are accessing the contents of the
Centimeters
type a lot, you could consider using a proper struct with a field to define the wrapper:This allows you to write
self.amt
instead of having to do the pattern matching. You can also define a function likefn cm(x: i32) -> Centimeters { Centimeters { amt: x } }
, called likecm(100)
, to avoid the verbosity of constructing a full struct.You can also access the inner values of a tuple struct using the
.0
,.1
syntax.For Rust version 1.10.0, it seems to me that type aliases would perfectly fit the situation you are describing. They simply give a type a different name.
Let's say all centimeters are
u32
s. Then I could just use the codeAny trait that
u32
has,Centimeters
would automatically have. This doesn't eliminate the possibility of addingCentimeters
toInches
. If you're careful, you wouldn't need different types.I made the derive_more crate for this problem. It can derive lots of traits for structs of which the elements implement them.
You need to add
derive_more
to yourCargo.toml
. Then you can write: