2017-02-01 5 views
3

Я действительно не знаю, как пройти мимо этого. Насколько я понимаю, words перемещается в закрытие (что отлично от меня, это единственное место, которое оно будет использоваться после этого), но должно быть & mut в соответствии с typed_some. То, что предлагает ошибка, звучит как приличная идея, просто эта часть находится в библиотеке, и я не знаю, было ли это что-то, что они могли бы реализовать.
on_edit documentation.Проблемы с изменчивостью в замыкании

extern crate cursive; 
extern crate rand; 

use cursive::Cursive; 
use cursive::views::{Dialog, TextView, EditView, LinearLayout}; 
use cursive::traits::Identifiable; 
use rand::Rng; 

fn main() { 
    // This really messes with stdout. Seems to disable it by default but when 
    // siv is running println prints in random places on the screen. 
    let mut siv = Cursive::new(); 
    siv.add_global_callback('q', |s| s.quit()); 

    let mut words = WordBar::new(); 

    siv.add_layer(Dialog::around(LinearLayout::vertical() 
      .child(TextView::new(words.update_and_get_bar()).with_id("target_field")) 
      .child(EditView::new() 
       .on_edit(move |s, input, _| words.typed_some(s, input)) 
       .with_id("input_field"))) 
     .title("Keyurses") 
     .button("Quit", |s| s.quit())); 

    siv.run(); 
} 


type WordList = Vec<&'static str>; 

#[derive(Debug)] 
struct WordBar { 
    words: WordList, 
    target_list: WordList, 
} 

impl WordBar { 
    fn new() -> Self { 
     WordBar { 
      words: include_str!("google-10000-english-usa.txt").lines().collect(), 
      target_list: vec!["foo"], 
     } 
    } 

    fn typed_some(&mut self, siv: &mut Cursive, input: &str) { 
     // See https://github.com/gyscos/Cursive/issues/102 
     // for discussion on this mess 

     let mut reset_input = false; 
     { 
      let target_word = siv.find_id::<TextView>("target_field").unwrap(); 
      if target_word.get_content() == input { 
       target_word.set_content(self.update_and_get_bar()); 
       reset_input = true; 
      } 
     } 
     if reset_input { 
      siv.find_id::<EditView>("input_field").unwrap().set_content(""); 
     } 
    } 

    fn rand_word(&self) -> &'static str { 
     let mut rng = rand::thread_rng(); 
     rng.choose(&self.words).unwrap() 
    } 

    fn update_and_get_bar(&mut self) -> String { 
     if self.target_list.len() > 0 { 
      self.target_list.pop(); 
     } 
     while self.target_list.len() < 5 { 
      let new_word = self.rand_word(); 
      self.target_list.push(new_word); 
     } 
     let mut bar_text: String = "".to_string(); 
     for word in &self.target_list { 
      if bar_text == "" { 
       bar_text = word.to_string(); 
      } else { 
       bar_text.push_str(" "); 
       bar_text.push_str(word); 
      } 
     } 
     bar_text 
    } 
} 

И ошибки

error: cannot borrow captured outer variable in an `Fn` closure as mutable 
    --> src/main.rs:20:45 
    | 
20 |     .on_edit(move |s, input, _| words.typed_some(s, input)) 
    |            ^^^^^ 
    | 
help: consider changing this closure to take self by mutable reference 
    --> src/main.rs:20:26 
    | 
20 |     .on_edit(move |s, input, _| words.typed_some(s, input)) 
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

Repo link, если вы хотели бы клонировать его, все подтолкнула. Commit 633ed60 будет конкретным.

+0

Я думаю, что вам, возможно, придется брать его как '& mut' внутри вашего закрытия, как это: .on_edit (MOVE | S, вход, _ | { пусть слова = & MUT слова; words.typed_some (s, вход) }) Я не могу его протестировать (на мобильном телефоне). –

+0

@WesleyWiser Спасибо, но я получаю ту же ошибку, просто слегка перефразированную https://bpaste.net/show/dde9cfc1c7fe – Powersource

+1

@WesleyWiser 'EditView :: on_edit' требует закрытия с помощью' Fn', что означает, что он не может мутировать его окружающей среды (кроме как через люк, например «RefCell», как показано в моем ответе). – user4815162342

ответ

6

on_edit действительно требует непреложного обратного вызова. Неясно, является ли это надзорным или сознательным решением разработчиков, но ваш код должен уважать его, если он закрывает доступ к окружающей среде без ограничений.

Ржавчина обеспечивает выходной люк для таких ситуаций: RefCell type. Вместо того, чтобы переместить WordBar в укупорочное средство, переместите RefCell<WordBar>, а затем используйте его метод borrow_mut() для заимствования с возможностью изменения, перемещая проверку займа во время выполнения. Это составляет:

fn main() { 
    let mut siv = Cursive::new(); 
    siv.add_global_callback('q', |s| s.quit()); 

    let words = ::std::cell::RefCell::new(WordBar::new()); 

    let text = words.borrow_mut().update_and_get_bar(); 
    siv.add_layer(Dialog::around(LinearLayout::vertical() 
           .child(TextView::new(text) 
             .with_id("target_field")) 
           .child(EditView::new() 
             .on_edit(move |s, input, _| 
               words.borrow_mut().typed_some(s, input)) 
             .with_id("input_field"))) 
        .title("Keyurses") 
        .button("Quit", |s| s.quit())); 

    siv.run(); 
} 

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

Это до вашего кода, чтобы гарантировать, что эта паника не срабатывает - в этом случае, убедившись, что действия, выполняемые закрытия переданного on_edit не вызывают on_edit не ссылаться на то же EditView до закрытия возвращается.

+0

Когда я лег спать (конечно), я подумал: «Может быть, это когда вам нужно использовать refcell?». Спасибо за объяснение! – Powersource

+1

@Powersource. По-прежнему неплохо было бы проверить у начинающих разработчиков, действительно ли 'on_edit' требует' Fn', или он может быть расслаблен, чтобы принять 'FnMut'. Если текущее ограничение существует по уважительной причине, обманывание его с помощью RefCell может в конечном итоге привести к панике во время выполнения. – user4815162342

+0

Да хорошая точка. В эти выходные я создам проблему. – Powersource

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