2016-06-26 4 views
3

나는 Hyper 0.10을 가진 간단한 메모리 내 URL 단축기를 구현하여 녹을 배우려고 시도하고있다. 나는 나의 핸들러에서 변경 가능한 HashMap을여 닫으려고에 의해 발생 생각 문제로 실행 해요 :하이퍼 핸들러간에 HashMap을 공유하려면 어떻게합니까?

fn post(mut req: Request, mut res: Response, short_uris: &mut HashMap<&str, &str>) { 
    let mut body = String::new(); 
    match req.read_to_string(&mut body) { 
     Ok(_) => { 
      let key = short_uris.len(); 
      short_uris.insert(&key.to_string(), &body.to_string()); 
      *res.status_mut() = StatusCode::Created; 
      res.start().unwrap().write(&key.to_string().into_bytes()); 
     }, 
     Err(_) => *res.status_mut() = StatusCode::BadRequest 
    } 
} 

fn get(req: Request, mut res: Response, short_uris: &HashMap<&str, &str>) { 
    match req.uri.clone() { 
     AbsolutePath(path) => { 
      match short_uris.get::<str>(&path) { 
       Some(short_uri) => { 
        *res.status_mut() = StatusCode::MovedPermanently; 
        res.headers_mut().set(Location(short_uri.to_string())); 
       }, 
       None => *res.status_mut() = StatusCode::NotFound 
      } 
     }, 
     _ => *res.status_mut() = StatusCode::BadRequest 
    } 
} 

fn main() { 
    let mut short_uris: HashMap<&str, &str> = HashMap::new(); 
    short_uris.insert("/example", "http://www.example.com"); 
    Server::http("0.0.0.0:3001").unwrap().handle(move |req: Request, mut res: Response| { 
     match req.method { 
      hyper::Post => post(req, res, &mut short_uris), 
      hyper::Get => get(req, res, &short_uris), 
      _ => *res.status_mut() = StatusCode::MethodNotAllowed 
     } 
    }).unwrap(); 
} 
src/main.rs:42:40: 42:46 error: the trait bound `for<'r, 'r, 'r> [[email protected]/main.rs:42:47: 48:3 short_uris:std::collections::HashMap<&str, &str>]: std::ops::Fn<(hyper::server::Request<'r, 'r>, hyper::server::Response<'r>)>` is not satisfied [E0277] 
src/main.rs:42 Server::http("0.0.0.0:3001").unwrap().handle(move |req: Request, mut res: Response| { 

Arc 스레드 사이의 HashMap를 공유하는 내가 사용해야합니까? 그렇다면 어떻게 생겼을까요? 또한 나는이 문제에 대해 완전히 틀릴 수도있다. 오류 메시지는 나에게 매우 모호합니다.

+0

HashMap을 전역으로 선언하지 않는 이유는 무엇입니까? –

+1

@ Dr.Sahib 나는 일반적으로 전역 상태를 피하려고 노력한다. 또한 글로벌 상태의 사용을 최소화 할 것을 권장하는 다음 SO 게시물을 읽었습니다. http://stackoverflow.com/questions/27791532/how-do-i-create-a-global-mutable-singleton. 그래서 전 세계적인 상태없이 그것을하려고했습니다. – forTruce

+0

그냥 밤에 녹을주의 깊게 살펴보면 여기에 더 좋은 오류 메시지가 나타납니다. "Fn 형을 구현하는 클로저가 예상되지만이 클로저는'FnMut' 만 구현합니다" – krdln

답변

4

다음번에 필요한 모든 use 신고서를 기재 해주세요. 감사합니다.

Fn 특성을 구현하는 폐쇄를 예상하지만,이 폐쇄는 단지 그 것을 의미 FnMut

구현 :

당신이 밤에 녹를 사용하는 경우이 오류 메시지가 덜 비밀입니다 Hyper에서는 스레드간에 공유가 공유되어야하므로 클로저는 변경 불가능하거나 공유 된 메서드를 통해서만 환경을 사용해야하므로 &mut short_uris의 사용은 여기에있는 가해자입니다. Rust에서 공유 스레드 안전성을 제공하려면 Mutex 또는 RwLock을 사용해야합니다. 하이퍼 (아마 후드 Arc의 폐쇄를 포장, 또는 범위 - 스레드 같은 것을 사용하여) 폐쇄 자체의 소유권을 관리 -

당신이 여기 있지 필요 Arc있습니다.

코드에 두 번째 문제가 있습니다. HashMap<&str, &str>을 사용합니다. &str은 빌린 참조입니다. 너가 녹에서 빌린 무언가가있을 때마다, 너는 너 자신에게 묻어야한다 - 어디에서? 여기서 여러분은 정말로 수명이 짧은 문자열 인 key.to_string()body.to_string()을 빌리려고합니다. 그것은 단지 작동하지 않습니다. 해시 맵을 완전히 소유하게하십시오 - HashMap<String, String>.

extern crate hyper; 

use hyper::server::{Request, Response, Server}; 
use std::collections::HashMap; 
use hyper::status::StatusCode; 
use hyper::uri::RequestUri::AbsolutePath; 
use hyper::header::Location; 
use std::io::prelude::*; 

fn post(mut req: Request, mut res: Response, short_uris: &mut HashMap<String, String>) { 
    let mut body = String::new(); 
    match req.read_to_string(&mut body) { 
     Ok(_) => { 
      let key = short_uris.len(); 
      short_uris.insert(key.to_string(), body); 
      *res.status_mut() = StatusCode::Created; 
      res.start() 
       .unwrap() 
       .write(&key.to_string().into_bytes()) 
       .unwrap(); 
     } 
     Err(_) => *res.status_mut() = StatusCode::BadRequest, 
    } 
} 

fn get(req: Request, mut res: Response, short_uris: &HashMap<String, String>) { 
    match req.uri { 
     AbsolutePath(ref path) => match short_uris.get(path) { 
      Some(short_uri) => { 
       *res.status_mut() = StatusCode::MovedPermanently; 
       res.headers_mut().set(Location(short_uri.to_string())); 
      } 
      None => *res.status_mut() = StatusCode::NotFound, 
     }, 
     _ => *res.status_mut() = StatusCode::BadRequest, 
    } 
} 

fn main() { 
    let mut short_uris: HashMap<String, String> = HashMap::new(); 
    short_uris.insert("/example".into(), "http://www.example.com".into()); 
    let short_uris = std::sync::RwLock::new(short_uris); 
    Server::http("0.0.0.0:3001") 
     .unwrap() 
     .handle(move |req: Request, mut res: Response| match req.method { 
      hyper::Post => post(req, res, &mut short_uris.write().unwrap()), 
      hyper::Get => get(req, res, &short_uris.read().unwrap()), 
      _ => *res.status_mut() = StatusCode::MethodNotAllowed, 
     }) 
     .unwrap(); 
} 

나는 또한 get 함수에서 불필요한 .clone() 제거있어 한을 : 여기에 컴파일 코드의 버전입니다. RwLock 잠금이 짧은 지속해야한다 (getpost 인수로 &RwLock<HashMap<String,String>>을 가지고 스스로 잠금을 수행해야합니다) -

이 코드는 컴파일하는 동안, 아직 완벽하지 있습니다. .unwrap()도 더 나은 방법으로 처리 될 수 있습니다. 또한 lockless 동시 해시 맵을 사용하는 것을 고려해 볼 수 있습니다. 일부 상자는 있어야하지만 주제가 아니므로 아무 것도 추천하지 않습니다.

+0

고마워요! 당신의 설명이 정말로 도움이되었습니다. – forTruce

관련 문제