Zipping vectors of the same type results different types within map closure

Viewed 49

Background

Given an enum variant type (non-copyable):

enum AstNode {
  Op(Func, Box<AstNode>, Box<AstNode>),
  Val(f64),
  // others...
}

Attempting to run an operation over two such vectors:

fn apply_func_iterative(func: Func, lhs: Vec<AstNode>, rhs: Vec<AstNode>) -> Vec<AstNode> {
    lhs.iter().zip(rhs).map(|(&l,r)| apply_func(func,l,r)).collect()  // l and r are declared differently!
}

fn apply_func(func: Func, lhs: AstNode, rhs: AstNode) -> AstNode {
    // magic happens here!
}

Within the closure, the lhs elements assume type l: &AstNode whereas the zipped rhs elements take type l: AstNode. (Note the different declarations in the closure tuple).

Questions

Why is this the case?

Is there a way to iterate elements of a vector by value instead of by reference? It would seem this is possible from the observed behavior of the zipped elements.

(In this example, this difference results in a slight oddity in syntax declaration, but in practice, I have hit up against the borrow-checker when passing the reference variable into a function)

Disclaimer: I am fairly new to Rust

1 Answers

The Iterator::zip method isn't doing anything special, it is simply combining both iterators. You're finding that lhs.iter() yields an Iterator<&AstNode> while rhs yields an Iterator<AstNode> (& vs non-&).

Is there a way to iterate elements of a vector by value instead of by reference? It would seem this is possible from the observed behavior of the zipped elements.

Yes, there is a way to control this behavior. The key is to notice that zip()'s argument rhs must implement the IntoIterator trait. Interally, zip() will call rhs.into_iter() to get an iterator from it. The conventional behavior is that .iter() only borrows the source and therefore can only provide references to its values. While .into_iter() consumes or "takes ownership of" the source and can yield owned values.

Combining those, you can do lhs.into_iter().zip(rhs) to get an iterator over values (AstNode, AstNode) or use lhs.iter().zip(rhs.iter()) to get an iterator over references (&AstNode, &AstNode).

Related