How to collect a map of enums?

I have an enum:

#[derive(Debug, Clone)]
enum Expression<'one, 'two> {
    Constant(f32),
    X,
    Y,
    Sum(&'one [Self]),
    Product(&'two [Self]),
}

I try to collect a map of some items inside of a sum:

impl<'one, 'two> Expression<'one, 'two> {
    fn simplify(&self) -> Self {
        match self {
            &Expression::Sum(sum) => {
		let new_expr = Expression::Sum(sum
						 .into_iter()
						 .map(|element| element.simplify())
						 .collect::<&[Expression]>());
		new_expr
	    },
            &Expression::Sum(_) => Expression::Constant(1f32),
            _ => self.clone(),
        }
    }
}

The Important part here is that to collect the expressions into a slice of expressions, I must implement the trait FromIterator trait for &[Expression].
The problem is I am having great difficulty implementing this trait.

Returning a reference to a value that is created in a function is impossible. So returning a slice from FromIterator::from_iter is impossible. Instead of borrowed slices you can use owned vectors, greatly simplifying your code:

#[derive(Debug, Clone)]
enum Expression {
    Constant(f32),
    X,
    Y,
    Sum(Vec<Self>),
    Product(Vec<Self>),
}

impl Expression {
    fn simplify(&self) -> Self {
        match self {
            Expression::Sum(sum) if sum.len() == 0 => Expression::Constant(1f32),
            Expression::Sum(sum) => {
                Expression::Sum(sum.into_iter().map(Expression::simplify).collect())
            }
            _ => self.clone(),
        }
    }
}
4 Likes

Yeah I was massively over complicating this. I was trying to make Expression fully immutable but I realise now that there was no need thanks for the solution. :heart:

1 Like

You can make Expression fully immutable by using a Box<[Self]> or an Arc<[Self]> instead. See this video for details.

Box<[T]> is no less mutable than Vec<T>. It may not be efficiently mutable because it lacks operations like Vec::push(), but given an &mut Box<[T]>, I can assign a new entire value to it — or mutate a single element. The same applies to Arc<[T]> except access to elements is conditional on there being no clones of the Arc.

In Rust, a lot of the reasons for wanting immutable data types don't apply because by default data can't be shared if it is being mutated, but if you want to do it anyway (perhaps because the type has invariants between fields) then you have to keep its fields private and offer only & access to them via getter methods.

4 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.