Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic math without copying in rust

I want to write some generic math functions, without assuming that my types are copyable. This seems not to be possible, since math operators consume the values, instead of borrowing them. So it is required to copy the object, just for simple math. I could also just move them, but this is not possible in borrowed context, which I need, when I want to mutate a struct.

Here some simple example, where are problems:

use std::ops::Add;

struct NoCopy<T>(T); //some non-copyable struct, (maybe a vector)
struct Cont<T>(NoCopy<T>); //some struct contaioning a noncopyable struct

impl<T: Add<Output=T>> Add for NoCopy<T> {
    type Output = NoCopy<T>;
    fn add(self, x: NoCopy<T>) -> NoCopy<T> {
        NoCopy(self.0+x.0)
    }
}

fn main() {
    let x = NoCopy(1);
    let cont = Cont(x);
    let rel = NoCopy(2);
    cont.0=cont.0+rel; //addition makes struct cont invalid, so i have to copy
}

And when I just want to calculate something with a not copyable object of a struct (for example the length of a vector), it won't work, since the value will either be consumed, so the struct gets invalid, or the borrow checker says "cannot move out of borrowed context". How would I correctly use a generic math, when mutating structs? Is it only possible for copyable types (or explicit cloning)?

like image 698
porky11 Avatar asked Feb 22 '17 23:02

porky11


1 Answers

One option is to implement Add on references:

impl<'a, T: Copy + Add<Output = T>> Add for &'a NoCopy<T> {
    type Output = NoCopy<T>;
    fn add(self, rhs: Self) -> NoCopy<T> {
        NoCopy(self.0+rhs.0)
    }
}

This is ok since shared references are Copy. Note I added a Copy constraint to T to make this implementation simple (true for integers); if T isn't copy then the one-liner method might need to change.

You do have to add references when using it, which is a shame, but it otherwise works:

fn main() {
    let x = NoCopy(1);
    let mut cont = Cont(x);
    let rel = NoCopy(2);
    cont.0=&cont.0+&rel;
}

(Playground)

like image 93
Chris Emerson Avatar answered Sep 30 '22 05:09

Chris Emerson