【发布时间】:2018-04-23 01:20:03
【问题描述】:
我真的在为闭包的生命周期而苦苦挣扎。我正在制作一个简单的刽子手游戏,所有连接都玩一个游戏。我正在尝试将闭包传递给将更新游戏然后广播 JSON 的频道,但我遇到了生命周期问题。
extern crate names;
extern crate ws;
#[macro_use]
extern crate json;
use names::{Generator, Name};
use std::collections::HashSet;
use std::sync::mpsc;
use std::thread;
use ws::{listen, CloseCode, Handler, Message, Result, Sender};
type Job = Box<FnMut(&mut Game) + Send>;
#[derive(Debug)]
struct Game {
word: Vec<String>,
guesses: HashSet<String>,
misses: u32,
progress: Vec<String>,
}
impl Game {
fn increment_miss(&mut self) {
self.misses += 1;
}
fn update_progress(&mut self, guess: &String) {
for (i, letter) in self.word.iter().enumerate() {
if letter == guess {
self.progress[i] = letter.clone();
}
}
}
fn status(&self) -> &str {
if self.misses > 10 {
"lose"
} else if self.progress == self.word {
"win"
} else {
"active"
}
}
}
struct Server {
out: Sender,
tx: std::sync::mpsc::Sender<Job>,
}
impl Handler for Server {
fn on_message(&mut self, msg: Message) -> Result<()> {
let string_msg = msg.to_string();
self.tx
.send(Box::new(move |mut game: &mut Game| {
if game.guesses.insert(string_msg.clone()) {
check_letter(&mut game, &string_msg);
};
let status = game.status();
let progress = game.progress.clone();
let guesses = game.guesses.clone().into_iter().collect::<Vec<String>>();
println!(
"guesses: {:?}, progress: {:?}, misses: {}, status: {}",
guesses, progress, game.misses, status
);
self.out.broadcast(json::stringify(object!{
"status" => "status",
"progress" => "progress",
"guesses" => "guesses",
"misses" => "misses",
}));
}))
.unwrap();
Ok(())
}
fn on_close(&mut self, code: CloseCode, reason: &str) {
match code {
CloseCode::Normal => println!("The client is done with the connection."),
CloseCode::Away => println!("The client is leaving the site."),
_ => println!("The client encountered an error: {}", reason),
}
}
}
fn check_letter(game: &mut Game, guess: &String) {
if game.word.contains(guess) {
game.update_progress(guess);
} else {
game.increment_miss();
}
}
fn generate_word() -> Vec<String> {
let mut generator = Generator::with_naming(Name::Plain);
generator
.next()
.unwrap()
.split("")
.map(|c| c.to_string())
.filter(|s| s != "")
.collect::<Vec<String>>()
}
fn start_game() -> Game {
let word = generate_word();
Game {
progress: vec!["".to_string(); word.len()],
word: word,
guesses: HashSet::new(),
misses: 0,
}
}
fn main() {
let (tx, rx) = mpsc::channel::<Job>();
thread::spawn(move || {
let mut game = start_game();
for mut received in rx {
received(&mut game)
}
});
listen("127.0.0.1:3000", |out| Server {
out: out,
tx: mpsc::Sender::clone(&tx),
}).unwrap();
}
我收到以下错误:
Compiling hang_man v0.1.0 (file:///Users/smykowski/workspace/rust/hang_man)
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:57:22
|
57 | self.tx.send(Box::new(move |mut game: &mut Game| {
| ______________________^
58 | | if game.guesses.insert(string_msg.clone()) {
59 | | check_letter(&mut game, &string_msg);
60 | | };
... |
75 | | }));
76 | | })).unwrap();
| |__________^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 54:5...
--> src/main.rs:54:5
|
54 | / fn on_message(&mut self, msg: Message) -> Result<()> {
55 | | let string_msg = msg.to_string();
56 | |
57 | | self.tx.send(Box::new(move |mut game: &mut Game| {
... |
78 | | Ok(())
79 | | }
| |_____^
note: ...so that the type `[closure@src/main.rs:57:31: 76:10 string_msg:std::string::String, self:&mut Server]` will meet its required lifetime bounds
--> src/main.rs:57:22
|
57 | self.tx.send(Box::new(move |mut game: &mut Game| {
| ______________________^
58 | | if game.guesses.insert(string_msg.clone()) {
59 | | check_letter(&mut game, &string_msg);
60 | | };
... |
75 | | }));
76 | | })).unwrap();
| |__________^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that expression is assignable (expected std::boxed::Box<for<'r> std::ops::FnMut(&'r mut Game) + std::marker::Send + 'static>, found std::boxed::Box<for<'r> std::ops::FnMut(&'r mut Game) + std::marker::Send>)
--> src/main.rs:57:22
|
57 | self.tx.send(Box::new(move |mut game: &mut Game| {
| ______________________^
58 | | if game.guesses.insert(string_msg.clone()) {
59 | | check_letter(&mut game, &string_msg);
60 | | };
... |
75 | | }));
76 | | })).unwrap();
| |__________^
【问题讨论】:
-
我在帮助您解决关闭问题时遇到了一些麻烦(我的大脑无法理解今天的生命周期问题......)......所以我决定稍微重写它以使用结构来执行你的工作反而。 You can see my rewrite in the Playground,虽然它不会在那里编译(它在本地编译)。
-
RE 关闭问题 - 他们将默认为
'static绑定,我无法为您缩小范围并使其编译。我觉得它有可能......我现在不知道怎么做。