2017-02-01 2 views
3

私は本当にこれをどうやって得るのか分かりません。私がそれを理解する限り、wordsはクロージャーに移動されます(これは私にとっては唯一の場所ですが、この後に使用される唯一の場所ですが)typed_someに従って& mutである必要があります。エラーが示唆しているのはまともなアイデアのようですが、その部分が図書館にあり、実装できるかどうかわかりません。
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あなたはむしろそれのクローンを作成したい場合は、すべてのは、プッシュ。具体的に633ed60をコミットします。

+0

); } (モバイルで)私はそれをテストすることはできません。 –

+0

@WesleyWiserありがとうございますが、私は同じエラーが発生しました。ちょっと言い換えて言います。https://bpaste.net/show/dde9cfc1c7fe – Powersource

+1

@WesleyWiser 'EditView :: on_edit'は' Fn'バウンドのクロージャを必要とします。環境(私の答えに示されているように 'RefCell'のようなエスケープハッチを除く)。 – user4815162342

答えて

6

on_edit実際には不変のコールバックが必要です。それが開発者の見落としや意識的な決定であるかどうかは明らかではありませんが、コードでは、クロージャーが囲む環境にのみアクセスできるようにすることで尊重する必要があります。

このような状況では、錆はエスケープハッチを提供します。RefCell typeWordBarをクロージャーに移動する代わりに、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に呼び出されることはありませんことを確認することにより、戻る。 ; words.typed_some(S、入力| | S、入力、_ { ましょう言葉=&mutの言葉 .on_edit(移動:私はあなたがこのようなあなたのクロージャ内として `&mut`それを借りる必要かもしれないと思う

+0

私はベッドに行ったとき(もちろん)私は実際には "おそらくこれはあなたがrefcellを使わなければならない時でしょうか?"と考えました。説明ありがとう! – Powersource

+1

@Powersource 'on_edit'が本当に' Fn'を必要としているのか、 'FnMut'を受け入れるために緩和できるのか、筆記体の開発者に確認することは良い考えです。現行の制約が正当な理由で存在する場合、 'RefCell'でそれを不正行為すると、最終的に実行時にパニックに陥る可能性があります。 – user4815162342

+0

良い点があります。今週末に問題を作ります。 – Powersource