ã¿ãªããããã«ã¡ã¯ïŒ
Rustã§åŒãç¶ãWebãµãŒãã¹ãäœæããŸãã ç®æ¬¡ïŒ
ããŒã1ïŒãããã¿ã€ãããŒã2ïŒINIãèªã¿ãŸãã å€éããŒã3ïŒã³ã³ãœãŒã«ããããŒã¿ããŒã¹ãæŽæ°ããããŒã4ïŒREST APIãžã®ç§»è¡ããŒã5ïŒããïŒïŒãã³ãã©ãŒããªãã¡ã¯ã¿ãªã³ã°ãããã³ãã¯ã
次ã«ãå®éã®APIãªã¯ãšã¹ããã³ãã©ãèŠãŠã以åã®æãã³ãŒããæžãæããŸãã äžè¬ã«ãããã¯ã·ãªãŒãºã®æåŸã®èšäºãªã®ã§ããªãã¡ã¯ã¿ãªã³ã°ãã¹ã¿ã€ã«ããã¯ãããããŠãã¹ãŠãã¹ãŠããããŸãã ãããæãé·ãéšåã§ãã
Arcã2åã¯ããŒã³åããçç±
APIãã¹ã調æŽããã³ãŒãã¯æ¬¡ã®ããã«ãªããŸãã
let sdb = Arc::new(Mutex::new(db)); let mut router = router::Router::new(); { let sdb_ = sdb.clone(); router.get("/api/v1/records", move |req: &mut Request| handlers::get_records(sdb_.clone(), req)); } { let sdb_ = sdb.clone(); router.get("/api/v1/records/:id", move |req: &mut Request| handlers::get_record(sdb_.clone(), req)); } âŠ
æå§ãã«ããã³ãã©ãŒèªäœã ããã§ãããšãã°ããã³ãã©ãŒ:: get_recordsïŒïŒïŒ
ãã³ãã©ãŒ:: get_records pub fn get_records(sdb: Arc<Mutex<Connection>>, req: &mut Request) -> IronResult<Response> { let url = req.url.clone().into_generic_url(); let mut name: Option<String> = None; if let Some(qp) = url.query_pairs() { for (key, value) in qp { match (&key[..], value) { ("name", n) => { if let None = name { name = Some(n); } else { return Ok(Response::with((status::BadRequest, "passed name in query more than once"))); } } _ => return Ok(Response::with((status::BadRequest, "unexpected query parameters"))), } } } else { return Ok(Response::with((status::BadRequest, "passed names don't parse as application/x-www-form-urlencoded or there are no parameters"))); } let json_records; if let Ok(recs) = ::db::read(sdb, name.as_ref().map(|s| &s[..])) { use rustc_serialize::json; if let Ok(json) = json::encode(&recs) { json_records = Some(json); } else { return Ok(Response::with((status::InternalServerError, "couldn't convert records to JSON"))); } } else { return Ok(Response::with((status::InternalServerError, "couldn't read records from database"))); } let content_type = Mime( TopLevel::Application, SubLevel::Json, Vec::new()); Ok(Response::with( (content_type, status::Ok, json_records.unwrap()))) }
ãã®çœ²åããã¯ããŒãžã£ãŒå
ã®ããŒã¿ããŒã¹ã§Arcã®ã¯ããŒã³ãäœæããå¿
èŠããã£ãçç±ã§ãã
pub fn get_records(sdb: Arc<Mutex<Connection>>, req: &mut Request) -> IronResult<Response> {
ã芧ã®ãšãããArcã¯å€ã«ãã£ãŠïŒã€ãŸããæææš©ä»ãã§ïŒããã«æž¡ãããŸãããããã¯åçŽã«ã³ããŒãããã¿ã€ãã§ã¯ãããŸããã ãã®ãããArcãè€è£œããŠãã³ãã©ãŒã«æž¡ããŸããã
ãã³ãã©ãŒã§äœãèµ·ããã
äžè¬ã«ããã³ãã©ãŒã¯åãã¿ã€ãã§ãããããget_recordsãæ¯èŒç詳现ã«èŠãã ãã§ããããã¯æãè€éã§ãã ãã³ãã©ãŒã¯ãã¿ãŒã³ãããã³ã°ãç©æ¥µçã«äœ¿çšããŠãšã©ãŒç¶æ³ãå€æããŸãã
æåã«ã
Url Ironããrust-url圢åŒã®
UrlãååŸããŸãã
let url = req.url.clone().into_generic_url();
ãããå®è¡ããŠ
query_pairsã¡ãœããã䜿çšããŸãããã®ã¡ãœããã¯ãURLãapplication / x-www-form-urlencodedããŒã¿ãšããŠè§£æããïŒå Žåã«ãã£ãŠã¯ïŒããŒãšå€ã®ãã¢ã®å埩åãè¿ããŸãã
ãããŠ
次ã«ããif letããšããæ°ããæ§æã瀺ãããã®æ¬è³ªã説æããŸãã
if let Some(qp) = url.query_pairs() { for (key, value) in qp {
ãã®ãšã³ããªã®æå³ããã§ã«æšæž¬ããŠããå¯èœæ§ããããŸãã if letã¹ããŒãã¡ã³ãã¯ãã¿ãŒã³ãšã®äžèŽãè©Šã¿ãæåããå Žåãif letã®åŸã®ãããã¯ã«å®è¡ãæž¡ããŸãã ãã®ãããã¯ã§ã¯ãå€ãé¢é£ä»ããã°ããã®ååïŒãã®å Žåã¯qpïŒã䜿çšã§ããŸãã å€ããã³ãã¬ãŒããšäžèŽãããããšãã§ããªãã£ãå ŽåïŒquery_pairsïŒïŒãNoneãè¿ããŸããïŒãelseãã©ã³ããå®è¡ãããŸã-éåžžã®ifã®ããã«èŠããŸãã
ç¡å¹ãªHTTPã¹ããŒã¿ã¹ãè¿ã
ãããã£ãŠãã€ãã¬ãŒã¿ãè¿ãããªãã£ãå Žåãããã¯ãšã©ãŒã§ãã
} else { return Ok(Response::with((status::BadRequest, âpassed names don't parse as application/x-www-form-urlencoded or there are no parametersâ))); }
ããã«ããµãŒããŒã®å¿çã説æãããã£ãå
ã®ã¿ãã«ããããŸãïŒHTTPã¹ããŒã¿ã¹ãšã¡ãã»ãŒãžã
ãªã¯ãšã¹ããã©ã¡ãŒã¿ãŒãååŸãã
ã€ãã¬ãŒã¿ãè¿ãããå Žåããããåé¿ããŠååãã©ã¡ãŒã¿ãååŸããååå€æ°ã«ä¿åããŸãã
let mut name: Option<String> = None; if let Some(qp) = url.query_pairs() { for (key, value) in qp { match (&key[..], value) { ("name", n) => { if let None = name { name = Some(n); } else { return Ok(Response::with((status::BadRequest, "passed name in query more than once"))); } } _ => return Ok(Response::with((status::BadRequest, "unexpected query parameters"))), } } }
ããã§ã«ãŒãã¯ãã€ãã¬ãŒã¿ããã€ãã¹ãããã¢ã®ãã¯ãã«ããç®çã®èŠçŽ ãåŒãåºããæææš©ã«åé¡ããªãããã«ããããã«å¿
èŠã§ãã ããããå®éã«ã¯ãååãšåŒã°ããèŠæ±ãã©ã¡ãŒã¿ãŒã1ã€ã ãäžããããŠããªãç¶æ³ã¯ãšã©ãŒã§ãã ã«ãŒããåé€ããŠã¿ãŸãããã
ãã©ã¡ãŒã¿ãŒã«ãã£ãŠãµã€ã¯ã«ãåé€ããŸã
.query_pairsïŒïŒã¯ãå®éã«ã¯Option <Vec <ïŒStringãStringïŒ>>ãè¿ããŸãã ãããã£ãŠããã¯ãã«ã®é·ããšåäžã®ãã©ã¡ãŒã¿ãŒã®ååãç°¡åã«ç¢ºèªã§ããŸãã
let mut name: Option<String> = None; if let Some(mut qp) = url.query_pairs() { if qp.len() != 1 { return Ok(Response::with((status::BadRequest, "passed more than one parameter or no parameters at all"))); } let (key, value) = qp.pop().unwrap(); if key == "name" { name = Some(value); } } else {
ããã§ããã¯ãã«ãè¿åããã®ã§ã¯ãªãããã®é·ãã確èªããèå³ã®ãããã©ã¡ãŒã¿ãŒãå³ã«åããŸãã
ããã«ã¯éèŠãªãã€ã³ãããããŸãïŒ
let (key, value) = qp.pop().unwrap();
popïŒïŒã䜿çšããããšãéèŠã§ã-æææš©ãæã€ãã¯ã¿ãŒèŠçŽ ãæäŸããŸãã éåžžã®ã€ã³ããã¯ã¹åŒã³åºãïŒqp [0]ïŒã¯ãªã³ã¯ãæäŸããå€ããã¢ããSomeïŒå€ïŒã«ç§»åããŠãã¹ãŠãååã«å
¥ããããšã¯ã§ããŸããã
æååæ¯èŒãïŒstrã§æ©èœããã®ã¯ãªãã§ããïŒ
ãŸãããã¯ã¿ãŒã®ãã¢ïŒStringãStringïŒã«æ ŒçŽãããŠããããšã«ã泚æããŠãã ããã ããããããŒããååããšçŽæ¥æ¯èŒããŸã-æååãªãã©ã«ïŒ
if key == "name" { name = Some(value); }
èŠããŠããããã«ãããã¯åïŒ 'static strã§ãã ãããæ©èœããã®ã¯ãStringãPartialEqãå®è£
ããŠïŒ 'a strãšæ¯èŒããããã§ãã
impl<'a> PartialEq<&'a str> for String
ãããã£ãŠãããã§ã¯åå€æã¯è¡ãããŸããã
ãã®ãããªåããªãã£ãå Žåãã¹ã©ã€ã¹æ§æã䜿çšããŠæååãïŒstrã«å€æã§ããŸããïŒããŒ[..]ã¯ãæååå
šäœã«æ²¿ã£ãŠã¹ã©ã€ã¹ãè¿ããŸããã€ãŸãã ãªã³ã¯ã¯åãã³ã³ãã³ãã®ïŒstrã§ãã
次ã«ãããŒã¿ããŒã¹ãžã®å®éã®ã¢ã¯ã»ã¹ãè¡ããŸãã
åæåãããŠããªãå€æ°-å±éºã§ããïŒ
ãŸããRESTã¢ã¯ã»ã¹ãã€ã³ããè¿ãJSONã¬ã³ãŒãã®ååã宣èšããŸãã
let json_records;
ããŒããå€ã§åæåããŸãããïŒ èªåã®è¶³ã§æ®åœ±ãããã§ããïŒ
ããããRustã¯å®£èšãããååãåæåãããŸã§äœ¿çšããŸããã ããšãã°ããã®ãããªã³ãŒãã§ã¯
fn main() { let a; if true { a = 5; } else { println!("{}", a); } }
ãšã©ãŒãçºçããŸãïŒ
test.rs:6:24: 6:25 error: use of possibly uninitialized variable: `a` [E0381] test.rs:6 println!("{}", a); ^
ããŒã¿ããŒã¹ããã¬ã³ãŒããèªã¿åããŸãã Option :: mapã䜿çšããŸã
次ã«ãããŒã¿ããŒã¹ãããšã³ããªãèªã¿åããŸãã
if let Ok(recs) = ::db::read(sdb, name.as_ref().map(|s| &s[..])) {
è°è«ã®äžã§å¥åŠãªããšãèµ·ãã£ãŠããã®ã¯ãªãã§ããïŒ
name.as_ref().map(|s| &s[..])
ãããã説æããŸãã ãŸãã:: db :: readïŒïŒã®çœ²åãèŠãŠãã ããïŒ
pub fn read(sdb: Arc<Mutex<Connection>>, name: Option<&str>) -> Result<Vec<Record>, ()> {
ã芧ã®ãšãããååã¯
Option<&str>
圢åŒã§ååãåã
Option<&str>
ã ååã®ã¿ã€ãã¯
Option<String>
ã§ãã ããããããã¯éèŠã§ã¯ãããŸãã
.as_ref()
ã¡ãœããã¯ã
Option<T>
ã
Option<&T>
å€æã
Option<&T>
-ãã®ããã«ããŠã
Option<&String>
ãååŸããŸãã
æ®å¿µãªããããªããªã
&String
ã¯ãªãã·ã§ã³ã«ã©ãããããèªåçã«
&str
å€æãããŸããã ãããã£ãŠãå¿åé¢æ°ã§ã¯äžèšã®ã¹ã©ã€ã¹æ§æã䜿çšããŸãã
.map(|s| &s[..])
.mapã¯ãé¢æ°ãOptionã®ã³ã³ãã³ãã«é©çšããTã
Option<T>
ããä»ã®ã¿ã€ãã«å€æããŸãã ãã®å Žåã
&String
ã
&str
å€æã
&str
ã ããã¯Haskell
fmap :: Functor f => (a -> b) -> fa -> fb
䌌ãŠããŸãã
埮åŠãªç¹ããããŸãã
name: Option<T>
ã§.mapãããã«åŒã³åºããŸããã§ããããªããªãã ãªã³ã¯ã¯ãåŒã³åºããããšãã«é¢æ°ãã©ã¡ãŒã¿ãŒã®ã¹ã³ãŒãå
ã§ã®ã¿æå¹ã«ãªããŸãã ãã®å Žåãã¯ããŒãžã£å
ã«ãªã³ã¯ãååŸããã¯ããŒãžã£ãåç¶ããŠããéã®ã¿ãªã³ã¯ãåç¶ããŸãã ãã ããã©ãã«ãä¿åãããããã©ã¡ãŒã¿ãŒãé¢æ°ã«æž¡ããšç Žæ£ãããŸãã ãã®ãããªãªã³ã¯ã¯äžæãªããžã§ã¯ãã«ãªããŸãã
handlers.rs:25:53ïŒ25:54ãšã©ãŒïŒ `s`ã¯ååãªé·ãã§ã¯ãããŸãã
handlers.rs:25 if OkïŒrecsïŒ= :: db :: readïŒsdbãname.mapïŒ| s |ïŒs [..]ïŒïŒ{
^
handlers.rs:25:23ïŒ25:60泚ïŒåç
§ã¯25:22ã®åŒã³åºãã«å¯ŸããŠæå¹ã§ãªããã°ãªããŸãã...
handlers.rs:25 if OkïŒrecsïŒ= :: db :: readïŒsdbãname.mapïŒ| s |ïŒs [..]ïŒïŒ{
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
handlers.rs:25:52ïŒ25:58泚ïŒ...ãã ããåçšããå€ã¯25:51ã®é¢æ°ã®ãã©ã¡ãŒã¿ãŒã®ã¹ã³ãŒãã§ã®ã¿æå¹ã§ã
handlers.rs:25 if OkïŒrecsïŒ= :: db :: readïŒsdbãname.mapïŒ| s |ïŒs [..]ïŒïŒ{
^ ~~~~~
.as_refïŒïŒã®å ŽåãOptionèªäœãåç¶ããŠããéã«ãªã³ã¯ãåç¶ããããããã¹ãŠãæ©èœããŸãã
ãããããã«ãã¹ã¬ããã«ã€ããŠã¯ã©ãã§ããããïŒ
:: db ::ãèŠãŠãè³è³ãããŠããããŒã¿ã¬ãŒã·ã³ã°ä¿è·ãã©ã®ããã«æ©èœããããèªãã§ã¿ãŸãããã
if let Ok(rs) = show(&*sdb.lock().unwrap(), name) { Ok(rs) } else { Err(()) }
showãåŒã³åºãããïŒ
pub fn show(db: &Connection, arg: Option<&str>) -> ::postgres::Result<Vec<Record>> {
ãã®é¢æ°ã¯Connectionãžã®ãªã³ã¯ãåãå
¥ãã
Arc<Mutex<Connection>>
ãŸãã åç
§ã«ãŠã³ã¿ãå±éããŠãã¥ãŒããã¯ã¹ããã£ããã£ããªãéããé¢å¿ã®ããããŒã¿ããŒã¹æ¥ç¶ã«ã¢ã¯ã»ã¹ã§ããŸããã åã·ã¹ãã ã¯ç¡å¹ãªç¶æ
ãè¡šçŸã§ããªãããã«ããŸãã
ã»ãšãã©éæ³
ãã®ããããã¥ãŒããã¯ã¹ãåŒãç¶ãããã§ãã åç
§ã«ãŠã³ã¿ãŒã«ãã¹ããããŠããŸãã ããã§ã¯ã2ã€ã®ããšãé¢ä¿ããŸããéåç
§æã®å€æãšãã¡ãœããåŒã³åºãæã®èªåéåç
§ã§ãã
ä»ã®ãšãããå¥åŠãªïŒ*ãç¡èŠããŠãsdb.lockïŒïŒèªäœãèŠãŠãã ããã sdbã¯Arcã§ããã
Arc<T>
ã¯
Deref<T>
å®è£
ããŠããŸãã
impl<T> Deref for Arc<T> where T: ?Sized type Target = T fn deref(&self) -> &T
ãããã£ãŠãå¿
èŠã«å¿ããŠ
Arc<T>
ã¯èªåçã«ïŒTã«å€æãããŸãã ããã«ããã
&Mutex<Connection>
ãåŸãããŸãã
次ã«ãã¡ãœãããåŒã³åºããšãã«èªåéåç
§ãäœçšããŸãã èŠããã«ãã³ã³ãã€ã©ã¯ã¡ãœããåŒã³åºããšåæ°ã®éåç
§ãæ¿å
¥ããŸãã
以äžã«ç°¡åãªäŸã瀺ããŸãã
struct Foo; impl Foo { fn foo(&self) { println!("Foo"); } } let f = Foo; f.foo(); (&f).foo(); (&&f).foo(); (&&&&&&&&f).foo();
æåŸã®4è¡ã¯ãã¹ãŠåãããšãè¡ããŸãã
RAIIã䜿çšãããã¥ãŒããã¯ã¹ã»ãŒããªãªãŒã¹
Mutex :: lockã¯ã
LockResult<MutexGuard<T>>
ãè¿ã
LockResult<MutexGuard<T>>
ã çµæã«ãããšã©ãŒãåŠçã§ãã
MutexGuard<T>
ã¯RAIIå€ã§ããã
MutexGuard<T>
äœçšãåæ¢ãããšããã«ãã¥ãŒããã¯ã¹ãèªåçã«éããŸãã
åã
&*
MutexGuard<T>
ãïŒTã«å€æã
MutexGuard<T>
-æåã«ãããéåç
§ããŠTãååŸãã次ã«ã¢ãã¬ã¹ãååŸããŠéåžžã®ãªã³ã¯ïŒTãååŸããŸãã
ãªãlockïŒïŒã
Arc<Mutex<Connection>>
ã§çŽæ¥æ©èœããMutexGuardãæåã§å€æããå¿
èŠãããã®ã§ããïŒ ããã¯ã¯ã¡ãœããã§ãããã¡ãœããåŒã³åºãã¯å®éã«ãªã³ã¯ãéåç
§ããã ãã§ãªããäžéšã®ãªã³ã¯ãä»ã®ãªã³ã¯ã«å€æããïŒã€ãŸãã
&*
é¡äŒŒããïŒããã§ãã é¢æ°ã«åŒæ°ãæž¡ãå Žåãããã¯æåã§è¡ãå¿
èŠããããŸãã
é£èŒ
ã¬ã³ãŒããåãåã£ãããããããJSONã«ã·ãªã¢ã«åããŸãã ãããè¡ãã«ã¯ã
rustc_serializeã䜿çšã
ãŸã ã
use rustc_serialize::json;
ã芧ã®ãšãããã¢ãžã¥ãŒã«ãã°ããŒãã«ã«ã€ã³ããŒãã§ããã ãã§ãªããåäžã®é¢æ°ãŸãã¯ãããã¯ã®ã¹ã³ãŒãå
ã§ãã€ã³ããŒãã§ããŸãã ããã¯ãã°ããŒãã«åå空éãè©°ãŸãããªãããã«ããã®ã«åœ¹ç«ã¡ãŸãã
ã·ãªã¢ã«åèªäœã¯ã次ã®ã³ãŒãã§å®è¡ãããŸãã
if let Ok(json) = json::encode(&recs) { json_records = Some(json); } ...
ãã®å Žåãã·ãªã¢ã©ã€ã¶ãŒã³ãŒãã¯èªåçã«çæãããŸãïŒ ã¬ã³ãŒãã®åãã·ãªã¢ã©ã€ãºå¯èœïŒããã³åæã«ãã·ãªã¢ã©ã€ãºå¯èœïŒãšããŠå®£èšããã ãã§ãã
#[derive(RustcEncodable, RustcDecodable)] pub struct Record { id: Option<i32>, pub name: String, pub phone: String, }
ãã¹ãŠãéãè¿ããŸã
æåŸã«ãé©åãªããããŒã䜿çšããŠJSONãæ£ããHTTPã§ã©ããããŠè¿ããŸãã
let content_type = Mime( TopLevel::Application, SubLevel::Json, Vec::new()); Ok(Response::with( (content_type, status::Ok, json_records.unwrap())))
æ®ãã®ãã³ãã©ãŒãåæ§ã«æ©èœãããããèªåã§ç¹°ãè¿ãã®ã§ã¯ãªããã³ãŒãããªãã¡ã¯ã¿ãªã³ã°ããŸãã
äžè¬çã«ãç§ãã¡ã®ããã°ã©ã ã¯çµãããŸããïŒ ããã§ããã°ãããé»è©±åž³ãã³ãã³ãã©ã€ã³ããã ãã§ãªããæµè¡ã®Web APIãããæŽæ°ã§ããŸãã åäœã確èªããã«ã¯ã
GitHubã® feature-completeã¿ã°ã䜿çšããŠã³ãŒãã®ããŒãžã§ã³ãååŸã
ãŸã ã
ãªãã¡ã¯ã¿ãªã³ã°ã¯ããã»ã©è€éã§ã¯ãããŸãããRustã³ãŒããçŸããããšã確信ãããããã«ããã®ããã»ã¹ã瀺ããŸãã æ©èœãå®è£
ããããã»ã¹ã§ç§ãã¡ãå¥ããèªã¿åãäžèœãªæ··ä¹±ã¯ãåã«ã©ãã·ã¥ã®çµæã§ãã Rustã¯ããã責ãããã®ã§ã¯ãããŸããããšã¬ã¬ã³ããªã³ãŒããæžãããšãã§ããŸãã
ã¯ããŒã³ãã¯ããŒã³ããŸãã
ãŸããåã®ããŒãã§èª¬æããäºéã¢ãŒã¯ã¯ããŒã³ã«ã€ããŠèª¬æããŸãã
{ let sdb_ = sdb.clone(); router.get("/api/v1/records", move |req: &mut Request| handlers::get_records(sdb_.clone(), req)); }
åã€ããšã¯éåžžã«ç°¡åã§ãã ãã³ãã©ãŒã®çœ²åãå€æŽããŸã:: get_records with
pub fn get_records(sdb: Arc<Mutex<Connection>>, req: &mut Request) -> IronResult<Response> {
ã«
pub fn get_records(sdb: &Mutex<Connection>, req: &mut Request) -> IronResult<Response> {
ãããŠäžè¬çã«ããã³ãã©ãŒãšããŒã¿ããŒã¹é¢æ°ã§ã¯ãã©ãã§ã
&Mutex<Connection>
ã䜿çšããŸãã ãã¹ãŠãäºéã¯ããŒãã³ã°ã¯ããå¿
èŠãããŸããã
{ let sdb = sdb.clone(); router.get("/api/v1/records", move |req: &mut Request| handlers::get_records(&*sdb, req)); }
巚倧ãªã¡ã€ã³ââãäžèŠã®äŸ¡å€ããããŸãã ãã¹ãŠã®ã¢ã¯ã·ã§ã³ãé¢æ°ã«åã蟌ãã§ãã¯ãŒã«ã§ã³ã³ãã¯ããªã¡ã€ã³ãååŸããŸãã
fn main() { let (params, sslmode) = params(); let db = Connection::connect(params, &sslmode).unwrap(); init_db(&db); let args: Vec<String> = std::env::args().collect(); match args.get(1) { Some(text) => { match text.as_ref() { "add" => add(&db, &args), "del" => del(&db, &args), "edit" => edit(&db, &args), "show" => show(&db, &args), "help" => println!("{}", HELP), "serve" => serve(db), command => panic!( format!("Invalid command: {}", command)) } } None => panic!("No command supplied"), } }
rustfmtïŒ
æåŸã«ãçãïŒ
rustfmt ïŒ RustãœãŒã¹ã³ãŒããã©ãŒããããŠãŒãã£ãªãã£ã¯ãŸã å®æããŠããŸããããå°ããªãããžã§ã¯ãã®ã³ãŒããè£
食ããã®ã«ãã§ã«é©ããŠããŸãã
ãªããžããªã®ã¯ããŒã³ãäœæããããcargo build --releaseãäœæããçµæã®å®è¡å¯èœãã¡ã€ã«ã$ PATHã®ã©ããã«ã³ããŒããŸãã 次ã«ããããžã§ã¯ãã®ã«ãŒãã§ã
$ rustfmt src / main.rs
ãããŠããã ãã§ãã
ãããžã§ã¯ãå
šäœã®ã³ãŒã
ã¯å³åº§ã«ãã©ãŒããããããŸãïŒ rustfmtã¯ä»ã®ã¢ãžã¥ãŒã«ãžã®ãªã³ã¯ããã©ãããããããã©ãŒãããããŸãã
gofmtãšã¯ç°ãªããrustfmtã䜿çšãããšããœãŒã¹ãæžãæããããªã詳现ãªã¹ã¿ã€ã«ãèšå®ã§ããŸãã
çŸåšã®ããã©ã«ãã¹ã¿ã€ã«ã¯ãã³ã³ãã€ã©ãèšè¿°ãããŠããã¹ã¿ã€ã«ã«äŒŒãŠããŸãã ãã ãã
å
¬åŒã®ã¹ã¿ã€ã«ã¬ã€ããå®æãããšãrustfmtãæŽæ°ãããŸãã
ãã®ãåççãªããªãã¡ã¯ã¿ãªã³ã°ã¯çµãããå§ãŸããŸã...ç©è°ãéžããã®ã§ãããééããªã楜ãããã®ã§ãããã¯ãã䜿çšããŠåæ§ã®ã³ãŒãã®æ®ãã®ç¹°ãè¿ããåé€ããŸãããã
ãã¯ã
ç§ã¯ã©ã®ãããªç¹°ãè¿ãã«ã€ããŠè©±ããŠããã®ã§ããïŒ ããã«ã€ããŠïŒ
{ let sdb = sdb.clone(); router.get("/api/v1/records", move |req: &mut Request| handlers::get_records(&*sdb, req)); } { let sdb = sdb.clone(); router.get("/api/v1/records/:id", move |req: &mut Request| handlers::get_record(&*sdb, req)); } { let sdb = sdb.clone(); router.post("/api/v1/records", move |req: &mut Request| handlers::add_record(&*sdb, req)); } { let sdb = sdb.clone(); router.put("/api/v1/records/:id", move |req: &mut Request| handlers::update_record(&*sdb, req)); } { let sdb = sdb.clone(); router.delete("/api/v1/records/:id", move |req: &mut Request| handlers::delete_record(&*sdb, req)); }
æããã«ãããã«ã¯ã³ãŒãã«åæ ã§ããªãã£ãããã€ãã®é«ã¬ãã«ã®æ§é ããããŸãã ãããã®ãããã¯ã¯ãã«ãŒã¿ãŒãåŒã³åºãå¿
èŠã®ããã¡ãœãããç°ãªããããéåžžã®é¢æ°ã§ãããã®ãªãã·ã§ã³ããã¹ãŠåŠçããããã«ãåŒæ°ã«å¿ããŠå¯Ÿå¿ããã¡ãœãããåŒã³åºãåæã«ãã£ãŠç
§åããå¿
èŠããããŸãã
ããã¯ãäžè¬çã«èšãã°ããªãã·ã§ã³ã§ããããã®ã³ãŒããè·å Žã§æžããå Žåããããããããå®è¡ããããšããŸãããããã§ã¯æ¥œããã§ãããRustã§ãã¯ããè©ŠããŠã¿ããã£ãã®ã§ãã ããã§ã¯å§ããŸãããã
ãŸããããã§ã®ç¹°ãè¿ãæ§é ã¯ãArcãè€è£œããŠããã¹ããŒãã¡ã³ããå®è¡ãããããã¯ã§ãã 察å¿ãããã¯ããæžããŸãããïŒ
macro_rules! clone_pass_bound { ($arc:ident, $stmt:stmt) => { { let $arc = $arc.clone(); $stmt; } } }
æåã®è¡ã¯ãclone_pass_boundãšãããã¯ãã®å®çŸ©ãéå§ããããšã瀺ããŠããŸãã ãã«ãªååã§ãããããŸããããŸããã§ããã ããã¯ããèªäœãçç¶ã§ãããããããåäœäžã®ã³ãŒãã§ã¯å®è¡ãã¹ãã§ã¯ãããŸããã ãããããã-ããã¯ä»ç§ãã¡ã®ã±ãŒã¹ã§ã¯ãããŸããã
Rustã®ãã¯ãã«ã¯åãä»ããããŠããã2ã€ã®åŒæ°-åèå¥åã®$ arcãšåæŒç®åã®$ stmtïŒæãstmtïŒãåããŸãã ããèŠããšãäžèŽãããã¯ãã®å®çŸ©ã®é¡äŒŒæ§ã«æ°ä»ãããšãã§ããŸã-ããã§ã¯ãåŒæ°ã®ç¹å®ã®çµã¿åãããç¹å®ã®æ¬äœãšæ¯èŒãããŸãã ãã¯ãã«ã¯ãmatchã®ãããªå€ãã®ãã©ã³ããå«ããããšãã§ããŸããããã¯ãååž°ã®å Žåã«åœ¹ç«ã¡ãŸãã
ç¢å°ã®åŸã«ã2çµã®ãã¬ãŒã¹ããããŸãã ãã¯ãèšè¿°ã®æ§æã«å¿ããŠãããã€ãã¯-éåžžãéåžžã®äžèŽã®å Žåãšåæ§ã«å¿
èŠã§ãã
2çªç®ã®ãã¢ã䜿çšããŠããã¯ãããããã¯ã«å±éããããšèšããŸãã ãããã¯å
ã§ãsdbã$ arcã«çœ®ãæããŠãã»ãŒéåžžã®ã³ãŒããèšè¿°ããŸãã ããã¯ç°¡åãªäžè¬åã§ãã ã¯ããŒãã³ã°ã®åŸã«ãªãã¬ãŒã¿ãŒãç¶ããŸãã
ããããã®ãã¯ãã®åŒã³æ¹ã§ãïŒ
clone_pass_bound!( sdb, router.get("/api/v1/records", move |req: &mut Request| handlers::get_records(&*sdb, req)))
ãããŸã§ã®ãšãããããªã¥ãŒã ã«é¢ããŠã¯äœãä¿åããŠããŸããããç解ã§ããªãé»è©±ããåããŠããŸããã ãããã絶æããªãã§ãã ãã-ç§ãã¡ã¯å§ãŸã£ãã°ããã§ãïŒ
ãã¯ãäžã®ãã¯ã
ããã§ãããŒã¿ããŒã¹ãžã®æ¥ç¶ãã«ãŒã¿ãŒãè¿œå ããã¡ãœããïŒgetãpostãªã©ïŒãå®çŸ©ãããã³ãã©ãŒã®ååã®4ã€ã®ãã©ã¡ãŒã¿ãŒã䜿çšããŠ1ã€ã®ãã³ãã©ãŒãèšè¿°ã§ããããšãæããã«ãªããŸããã ãã®ããã®ãã¯ããæžããŸãããã
macro_rules! define_handler { ($connection:ident, $router: ident.$method:ident, $route:expr, $handler:path) => { clone_pass_bound!( $connection, $router.$method( $route, move |req: &mut Request| $handler(&*$connection, req))); } }
ããã§ã¯ããŸãããã¯ãåŒã³åºããšéåžžã®ãã¿ãŒã³ãããã³ã°ã®é¡äŒŒæ§ãããäžåºŠåŒ·èª¿ãã䟡å€ããããŸãã ã芧ã®ãšããããã¯ãåŒæ°ã®åºåãæåã¯ã³ã³ãã§ããå¿
èŠã¯ãããŸãããéåžžã®ã³ãŒããšã®é¡äŒŒæ§ãé«ããããã«ãã«ãŒã¿ãŒãšãã®ã¡ãœããããããã§åºåããŸããã
次ã«ããã¹ãŠã®å
·äœçãªååããã¯ãã®ã¡ã¿å€æ°ã«çœ®ãæããŠã以åã®ãã¯ããåŒã³åºããŸã-ããã»ã©æããé£ããããããŸããã éåžžããããã®ãã¯ãã¯äž¡æ¹ãšãæåã®è©Šè¡ã§äœæããŸããã
ããã§éåžžèãªãã¯ãã20è¡äœæããæçµçã«ã«ãããããã³ãŒããæžå°ãå§ããŸããã
define_handler!(sdb, router.get, "/api/v1/records", handlers::get_records); define_handler!(sdb, router.get, "/api/v1/records/:id", handlers::get_record); define_handler!(sdb, router.post, "/api/v1/records", handlers::add_record); define_handler!(sdb, router.put, "/api/v1/records/:id", handlers::update_record); define_handler!(sdb, router.delete, "/api/v1/records/:id", handlers::delete_record);
ããã¯å¶éã§ã¯ãããŸãããæåŸã®ãã¯ããå®çŸ©ããŸããããã«ãããå®çŸ©ãéåžžã«ã³ã³ãã¯ãã«ãªããéåžžã«ç解ãããããªããŸãã ããã§ãã³ãŒãã®å€æŽéšåãéåžžã«æçœã«ãªããã³ãŒããå®å
šã«ä¹Ÿç¥ãããã®ã«äœã劚ããããŸããã
æåŸã®ãã¯ãã§ã¯ãããã1ã€ã®éèŠãªç¬éããããŸãã
ãã¯ããã©ã€ã
æåŸã®ãã¯ãã¯æ¬¡ã®ããã«ãªããŸãã
macro_rules! define_handlers_family { ($connection:ident, $router:ident, $( [$method:ident, $route:expr, $handler:path]),+ ) => { $( define_handler!($connection, $router.$method, $route, $handler); )+ } }
ããªãå°ããã§ãã éèŠãªç¹ã¯ãåŒæ°ã«åçŸæ§ãå°å
¥ããããšã§ãïŒ
($connection:ident, $router:ident, $( [$method:ident, $route:expr, $handler:path]),+ ) => {
$( ⊠),+
ã¯ããã®ãã¯ããåŒã³åºããããšãã«ãæ¬åŒ§ã§å²ãŸããã°ã«ãŒãã1å以äžç¹°ãè¿ãå¿
èŠãããããšãæå³ããŸãã æ£èŠè¡šçŸã®ããã«èŠããŸãã
次ã¯ãã¢ã³ã¹ã¿ãŒãã¯ãã®æ¬äœã§ãã æåã«ç§ã¯ãã®ããã«æžããïŒ
define_handler!($connection, $router.$method, $route, $handler);
ã³ã³ãã€ã©ãå察ããããšïŒ
main.rs:134:46: 134:53 error: variable 'method' is still repeating at this depth main.rs:134 define_handler!($connection, $router.$method, $route, $handler); ^~~~~~~
å
ã»ã©èšã£ãããã«ã$ã¡ãœããã$ã«ãŒãã$ãã³ãã©ãå®çŸ©ããåŒã³åºãã®éšåã¯ç¹°ãè¿ãããšãã§ããŸãã Rustãã¯ãã«ã¯ãåŒã³åºãã®ç¹°ãè¿ãã®ç¹å®ã®ãã¬ãã«ãã«ããã¡ã¿å€æ°ã䜿çšããå Žåãåãç¹°ãè¿ãã¬ãã«ã«ããå¿
èŠããããšããã«ãŒã«ããããŸãã
ãã®ããã«èããããšãã§ããŸã-ãã¯ãåŒã³åºããã©ã¡ãŒã¿ãŒã®ã¿ãã«ã¯ã察å¿ããããã£ãšåæã«ç§»åãããŸãã ã€ãŸã 1ã€ã®ãã©ã¡ãŒã¿ãŒã»ããã¯1ã€ã®ããã£ã«å¯Ÿå¿ããå¿
èŠããããŸãã ãããã£ãŠããã¯ãã®æ§é ãç解ãããããªããŸã-äœã¯ææŠã®ããã«ãªããŸãã
ããã§ããã¯ãã1ã€ã ãã®ããã«èšé²ãããŸãããåŒã³åºããã©ã¡ãŒã¿ãŒã¯ç¹°ãè¿ãããŸãããããã£ãç¹°ãè¿ãããšã¯ã§ããŸããã ããã§ã¯ãæ¬äœã«$ã¡ãœãããæ£ç¢ºã«é
眮ããå¿
èŠããããŸããïŒ æ確ã§ã¯ãããŸããã ããã§ã¯ããã®ãããªç¶æ³ãåé¿ããããã«ããã©ã¡ãŒã¿ãããã£ãšã段éçã«ãåæããã«ãŒã«ãèæ¡ãããŸããã
ç§ãã¡ã«ãšã£ãŠãããã¯ãã¹ãŠããã©ã¡ãŒã¿ãŒãšåãåçŸæ§ä¿®é£Ÿåã§ããã£ãã©ããããå¿
èŠãããããšãæå³ããŸãã
$( define_handler!($connection, $router.$method, $route, $handler); )+
ããã§ã$ã¡ãœããã$ã«ãŒããããã³$ãã³ãã©ãŒãéè€ãã©ã¡ãŒã¿ãŒã«å¯Ÿå¿ããŸãã ãŸãã$æ¥ç¶ãš$ã«ãŒã¿ãŒã¯ãã°ããŒãã«ãã§ãããããã¯ç¹°ãè¿ãæ§ã®ä¿®é£Ÿåã§ã¯ãªããããåæ¬äœã§è€è£œãããŸãã
ãã®æŽè³ã®å ±é
¬ãšããŠãAPIã®ãã¹ãŠã®ãã¹ã®çŸããå®çŸ©ãååŸããŸãã
define_handlers_family!( sdb, router, [get, "/api/v1/records", handlers::get_records], [get, "/api/v1/records/:id", handlers::get_record], [post, "/api/v1/records", handlers::add_record], [put, "/api/v1/records/:id", handlers::update_record], [delete, "/api/v1/records/:id", handlers::delete_record])
äžå¿
èŠãªéè€ã¯ãªããæçµããŒãžã§ã³ã§ã¯ãåå¿è
ã«ã¯æ¯èŒçæ確ã«èŠããŸãã
Rustã®ãã¯ãã¯è¡ççã§ããããšã«æ³šæããŠãã ãã-ãã¯ãå
ã®ååãšå€éšã®ååã®è¡çªã¯é€å€ãããŸãã
ãããããã»ãšãã©å¿ããŠããŸã£ã-ã³ã³ãã€ã©ãªãã·ã§ã³--pretty-print = expandã¯ãã¯ãã®ãããã°ã«å€§ãã«åœ¹ç«ã€ã ãã®ããããã¯ããæšæºåºåã¹ããªãŒã ã«å±éããåŸãã³ãŒããåºåããŸãã Cããã³C ++ã³ã³ãã€ã©ã®-Eãªãã·ã§ã³ã«äŒŒãŠããŸãã
ããããïŒ
ããã ãã§ã ããã§ãã¹ãŠã§ãããã®ã·ãªãŒãºã®èšäºã¯ãWebãå«ãRustã§ã³ãŒãã®æ§ç¯ãéå§ã§ããã»ã©ååã«èªã£ããšæããŸãã
ãã§ã«Rustã§äœããå§ããŠããå Žåã¯ãã³ã¡ã³ãã«æžããŠãã ããã ãŸããéäžã§çºçãã質åã§
ãã£ããã«ãŒã ã«ã¢ã¯ã»ã¹ããŸãã圌ãã¯ããã§åãã§ãæäŒãããŸãã