У меня есть цикл, в котором программа получает сообщение через веб-сокет и записывает информацию о пользователе (из сообщения) в «базу данных?».
#[derive(Debug)]
struct ChatUser{
name: String,
password: String,
}
static NEW_USER_ID: AtomicUsize = AtomicUsize::new(1);
type UserDB = Arc<RwLock<HashMap<usize, ChatUser>>>;
async fn web_socket(mut ws: WebSocket, State(state): State<UserDB>) {
let new_id = NEW_USER_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
while let Ok(Message::Text(message)) = ws.next().await.unwrap(){
let user_info: Value = serde_json::from_str(&message.trim()).unwrap();
let (name, password) = (user_info["name"].to_string(), user_info["password"].to_string());
state.write().await.insert(new_id, ChatUser { name: name, password: password }).expect("cant write");
println!("{:?}",state);
}
}
state.write работает неправильно при запуске в цикле... вне цикла все работает правильно
Можно ли взять значения из цикла? или записать их в штат каким-то другим способом?
если я запущу код и отправлю сообщение в сокет
thread 'tokio-runtime-worker' panicked at src/main.rs:41:93:
cant write
stack backtrace:
0: rust_begin_unwind
at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/std/src/panicking.rs:652:5
1: core::panicking::panic_fmt
at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/panicking.rs:72:14
2: core::panicking::panic_display
at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/panicking.rs:262:5
3: core::option::expect_failed
at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/option.rs:1995:5
4: core::option::Option<T>::expect [............]
как я могу это исправить?
«не могу написать» <--- это форма сообщения state.write.await.insert.expect («не могу написать»)
Insert записывает новое значение внутрь, не так ли?
Да, но возвращаемое значение — это Option<V>
, Some(V)
старого значения, если ключ уже находится в HashMap
, и None
, когда это совершенно новый ключ. Т.е. когда вы впервые вставите ключ, он вернется None
, вам нужно просто let _ =
его .
Сообщение в ожидании показывает природу путаницы. Если бы state.write()
возвращал Result
, то expect("can't write")
имело бы смысл и было бы необходимо, но оно было бы в другом месте: state.write().await.expect("can't write").insert(...)
. Но это не так, и ваш expect()
помещается в заявку на Option
, возвращенный HashMap::insert()
. Сообщение, отражающее то, что он делает, будет чем-то вроде expect("didn't overwrite previous value")
. Поскольку вы не хотите утверждать, что перезаписали предыдущее значение, expect()
можно удалить.
Я дал это сообщение, чтобы понять, какая строка кода вызывает ошибку, никакого особого смысла сообщению я не придал
Есть 2 проблемы
Возвращаемое значение HashMap::insert()
равно Option<V>
, что не означает, что вставка прошла успешно, однако она всегда успешна.
Some(V)
старого значения, когда ключ уже есть в HashMap, иNone
когда это совершенно новый ключ. Т.е. когда вы впервые вставляете ключ, он возвращает None, вам нужно просто let _ =
его.use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
// the first time inserting a key return `None`
assert_eq!(None, map.insert("My Key", 69));
// subsequent insertion return the already inserted value
assert_eq!(Some(69), map.insert("My Key", 420));
}
Это неправильный вопрос, но в любом случае вот ответ,
Вы можете заменить цикл while
на цикл loop
и разорвать цикл со значением.
let error: std::io::Error = loop {
// do whatever task
// blah blah blah
//...
// some how encounter a Result type
let result: Result<i32, std::io::Error> = /* some error-able things */;
let ok_i32 = match result {
// safely unwrap the result into Ok(_)
Ok(i) => i,
// return the error
Err(e) => break e,
};
// Keep doing whatever task
drop(ok_i32);
};
let _ = ...
является ненужным и унидиоматическим для HashMap::insert()
. Option
— это не Result
, и его можно просто выбросить. Другими словами, вместо let _ = map.insert(...)
, как предложено в ответе, можно просто использовать map.insert(...)
.
HashMap::insert
вернет предыдущее значение, если оно существовало, поэтому ваш.expect()
запаникует, если значение еще не существует, а это, я думаю, не то, что вы хотели (в конце концов, этоnew_id
). Просто уберите.expect()
.