Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how does `flat_map` affect my code?

Tags:

rust

I have been working on the following code for my whole day,(here is the playpen)

/// The rule that moves state from one to another.
///
/// `S` - the type parameter of state.
///
/// `T` - the type parameter of input symbol.
#[deriving(PartialEq, Eq, Hash)]
pub struct Rule<S, T> {
  pub state: S,
  pub symbol: Option<T>,
  pub next_state: S
}

impl<S: PartialEq, T: PartialEq> Rule<S, T> {
  /// determine whether the rule applies to the given state and symbol
  pub fn apply_to(&self, state: &S, symbol: &Option<T>) -> bool {
    self.state == *state && self.symbol == *symbol
  }
}

/// The transition relation in NFA,
/// containing all the rules needed by the NFA.
pub struct NFATransitions<S, T> {
  pub rules: HashSet<Rule<S, T>>
}

impl<S: Eq + Hash + Clone, T: Eq + Hash> NFATransitions<S, T> {

  pub fn next_states(&self, states: &HashSet<S>, symbol: &Option<T>) -> HashSet<S> {
    states.iter().flat_map(|state| {
      // error goes here: borrowed value does not live long enough
      self.next_states_for(state, symbol).iter().map(|s| s.clone())
    }).collect()

    // Howover, the following code which have the same behavior can compile

    // let mut result = HashSet::new();
    // for state in states.iter() {
    //   result.extend(self.next_states_for(state, symbol).iter().map(|s| s.clone()));
    // }
    //
    // result
  }

  /// get the next state for the given state and symbol
  fn next_states_for(&self, state: &S, symbol: &Option<T>) -> HashSet<S> {
    self.rules.iter().filter_map(|rule| {
      if rule.apply_to(state, symbol) { Some(rule.next_state.clone()) } else { None }
    }).collect()
  }
}

The code is just a wrapper of a hashset used for the nfa transition rules.(It's not what I'm concerned)

The flat_map is where I got compile error. It seems strange to me, as the commented lines, which I think have same behavior as the flat_map, can do well.

I cannot figure out how the error: borrowed value does not live long enough error comes out.

Any ideas ?

like image 869
Windor C Avatar asked Oct 07 '14 16:10

Windor C


1 Answers

The issue here is the iter(), this is tied to the lifetime of the result of next_states_for(), and is an iterator of &-pointers.

Since next_states_for() already clones stuff for you, into_iter() is what you want, which moves the items out of the collection.

  pub fn next_states(&self, states: &HashSet<S>, symbol: &Option<T>) -> HashSet<S> {
    states.iter().flat_map(|state| {
      // error goes here: borrowed value does not live long enough
      self.next_states_for(state, symbol).into_iter()
    }).collect()
  }

The closure captures by reference, which is why this is different from the for loop.

like image 69
Manishearth Avatar answered Nov 15 '22 14:11

Manishearth