7

Hyper 0.10 で簡単なインメモリ URL 短縮機能を実装して Rust を学ぼうとしています。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> [closure@src/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もしそうなら、それはどのように見えますか?また、私はこの問題について完全に間違っている可能性があります。エラーメッセージは私には非常に不可解です。

4

1 に答える 1

11

use次回は必要な申告書をすべて含めてください。よろしくお願いします。

ナイトリー Rust を使用している場合、エラー メッセージはそれほどわかりにくいものになります。

Fnトレイトを実装するクロージャーを期待していましたが、このクロージャーは実装するだけですFnMut

つまり、Hyper はスレッド間でクロージャを共有する必要があるため、クロージャは不変メソッドまたは共有メソッドを介してのみ環境を使用する必要があり&mut short_urisます。Rust で共有スレッドセーフな可変性を提供するには、Mutexまたはを使用する必要がありますRwLock

ここでは必要ないことに注意してください。HyperArcは、クロージャ自体の所有権を管理します (おそらく、クロージャをArcフードの下にラップするか、スコープ付きスレッドのようなものを使用します)。

コードには 2 番目の問題もありますHashMap<&str, &str>&strはお借りした参考書です。Rust で何かを借用するたびに、自問する必要があります – どこから? ここでは、本当に短命の文字列から借用しようとしています –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();
}

.clone()また、get関数内の不要なものを取り除きました。

このコードはコンパイル中ですが、まだ完全ではないことに注意してください。RwLockロックの持続時間は短くなるはずです (get引数としてpost取り、それ自体でロックを実行する必要があります)。&RwLock<HashMap<String,String>>また.unwrap()、より良い方法で処理される可能性があります。ロックレスの同時ハッシュマップを使用することも検討できます。そのためのクレートがいくつかあるはずですが、私はこのトピックに興味がないので、お勧めしません。

于 2016-06-27T00:56:56.233 に答える