2015-04-22 6 views
2

У меня возникла проблема с написанием Lexical Analyzer в Rust, где некоторые функции начинают жаловаться на простые фрагменты, которые иначе выглядели бы безобидными. Это начинает раздражать, поскольку сообщения об ошибках не помогают мне определить причину моих проблем, и поэтому это второй раз, когда я обращаюсь к одной и той же программе на той же неделе (предыдущий вопрос here).Путаница с недолговечными жизненными значениями, которые (на поверхности) кажутся совершенно безопасными

Я прочитал книгу, я понял все, что мог. Я также смотрел/читал многочисленные другие статьи и видеоролики, в которых обсуждалось время жизни (как явное, так и неявное), и по большей части концепция заимствований и перемещений имеет смысл, за исключением случаев, подобных следующим:

У моего лексера есть next Функция, цель которой - заглянуть вперед в следующий символ и вернуть его.

struct Lexer<'a> { 
    src: str::Chars<'a>, 
    buf: String, 
    // ... not important 
} 

impl<'a> Lexer<'a> { 
    // ... not relevant 

    // originally this -> Option<&char> which caused it's own slew of problems 
    // that I thought dereferencing the character would solve. 
    fn next(&self) -> Option<char> { 
     let res = self.src.peekable().peek(); 
     // convert Option<&char> to Option<char> 
     match res { 
      Some(ref c) => Some(*c.clone()), 
      None => None 
     } 
    } 

    // ... not relevant 
} 

ошибка, что я получаю, делая это:

error: borrowed value does not live long enough 
     let res = self.src.peekable().peek(); 
       ^~~~~~~~~~~~~~~~~~~ 

То, что я понял из этой ошибки в том, что значение из peekable() не живут достаточно долго, какой вид имеет смысл меня. Я ссылаюсь только на возврат в этой строке и вызывая другую функцию, которая, как мне кажется, возвращает указатель на символ в следующем месте с итератором. Мой наивный решение это было:

let mut peeker = self.src.peekable(); 
let res = peeker.peek(); 

Если я реализую это решение, я вижу другую ошибку, которая также не имеет смысла для меня:

error: cannot move out of borrowed content 
     let mut peeker = self.src.peekable(); 
         ^~~~ 

Я не совсем уверен, что движется self из заимствованного контекста здесь (я знаю, что это заимствовано из &self, но не уверен, что перемещение его из заимствованного контекста.

EDIT

Я предложил вопрос с деталями, которые были дико неточными. Часть сообщения, содержащая эти детали, была обновлена ​​с фактическими фактами - я перепутал две разные ситуации, в которых я столкнулся с подобной ошибкой (по крайней мере, по мне).

+0

Вы уверены, что ошибка peeker имеет такое же сообщение об ошибке? – bluss

+0

Нет, я, должно быть, смутил это чем-то другим. –

+1

.peekable() - это адаптер, поэтому он пытается вывести 'self.src' и вставлять его сам по себе, предоставляя вам новый итератор. Это не похоже на то, что вы хотите. Вы можете даже .clone() итератор Chars вместо этого, если хотите посмотреть вперед. – bluss

ответ

5

Начнем со второй ошибки.

Как упоминалось в комментариях, Iterator::peekable является итераторным адаптером, который потребляет итератор, который собирается сделать peekable. Небольшое воспроизведение:

let values = [1,2,3]; 
let mut iterator = values.iter(); 
iterator.peekable(); // Consumes `iterator` 
iterator.next(); // Not available anymore! 

Вы можете использовать Iterator::by_ref, чтобы получить ссылку, которая затем может сам потребляться. Обратите внимание, что базовый итератор будет продвигаться!

let values = [1,2,3]; 
let mut iterator = values.iter(); 
iterator.by_ref().peekable(); 
iterator.next(); 

В вашем случае, вы пытаетесь потреблять значение из заимствованных структур (через &self), который имеет конкретную ошибку cannot move out of borrowed content.


Давайте посмотрим на исходное сообщение об ошибке:

let values = [1,2,3]; 
let next = values.iter().peekable().peek(); 

Проблема здесь состоит в том, что peek возвращает ссылку . Это имеет смысл, так как мы не знаем, может ли элемент, который мы итерируем, Copy. Однако эта ссылка должна где-то жить. Это место для жизни - это итератор Peekable! Peekable выделяет достаточно места для хранения «следующего» элемента. Когда вы вызываете peek, он продвигает базовый итератор, сохраняет значение и возвращает ссылку. Проверьте подпись функции для peek, чтобы увидеть это захваченный в коде:

fn peek(&mut self) -> Option<&I::Item> 

Вы можете повторно добавить время жизни, чтобы быть явным:

fn peek<'a>(&'a mut self) -> Option<&'a I::Item> 

В версии одной строки, вы создаете, а затем уничтожитьPeekable, так что жить некуда, поэтому эта ссылка умирает в том же самом заявлении.

+0

Я рад, что понял, почему оригинал не работает. Несмотря на то, что потребление переменной, например, «peekable», потребляет, является итератором, называющим функцию видом странного побочного эффекта? Это не то, что я когда-либо ожидал (вызвать случайную функцию и потерять переменную, из которой я звонил). Я бы не подумал об этом. «By_ref» упоминается, хотя кажется, что я хочу. Я хочу, чтобы в мой итератор был живой «Peekable», чтобы я мог потреблять и заглядывать. Подглядывание используется, чтобы определить, продолжит ли лексер следующий символ для текущего токена. –

+1

@BrandonBuck Я бы не назвал это побочным эффектом * - вы просто перемещаете итератор по-значению в другой итератор. Вот почему [подпись функции] (http://doc.rust-lang.org/std/iter/trait.Iterator.html#method.peekable) показывает аргумент как 'self' not' & self'. Это сильная выгода от модели владения Rust, и вы научитесь любить ее для производительности и эксплицитности. – Shepmaster

+0

Иногда это расстраивает, когда я ожидаю, что все будет в безопасности, если Руст не увидит того же самого пути. –

 Смежные вопросы

  • Нет связанных вопросов^_^