Share
Embed
Transcript
22 slides
-
▶ Rust ྺ΄Μͷগ͠ ▶ ͱͱܕͷڧ͍ؔܕݴޠ͕͖Ͱɺܕਪύλʔϯ Ϛονͷ͑Δ Rust ͳΜͱͳ͑ͨ͘ ▶ ҰํͰ
Rust ͷγεςϜϓϩάϥϛϯάݴޠͱͯ͠ͷʁ੍ ʹͿ͔ͭΔ͜ͱ͋ͬͨ ▶ ΫϩʔδϟؔܕݴޠͰೃછΈͷਂ͍֓೦͕ͩɺRust Ͱ ͏ࡍʹҙ͕ඞཁͱ͍͏యܕతͳྫͩͱײͨ͡ͷͰɺΫ ϩʔδϟͷΛ͠·͢ ▶ Rust ૉਓͳͷͰ͍͚ٙͬͯͨͩΔͱ 3 / 22 -
Ϋϩʔδϟͱ ▶ ؔͱؔதʹݱΕΔมΛධՁ͢ΔͨΊͷڥͷ ▶ SICP ͷۜߦޱ࠲ͷྫ (define (make-withdraw balance) (lambda
(amount) (if (>= balance amount) (begin (set! balance (- balance amount)) balance) "Insufficient␣funds")))) (define W1 (make-withdraw 100)) (define W2 (make-withdraw 100)) (W1 10) ; => 90 (W1 20) ; => 70 (W1 80) ; => "Insufficient funds" (W2 40) ; => 60 4 / 22 -
▶ OCaml ͷ߹ɺࢀর͚ͩѻ͍Λม͑ͯޙ΄΅ͦͷ·· let make_withdraw (balance : int ref) :
int -> result = fun amount -> if !balance >= amount then (balance := !balance - amount; Ok !balance) else Err "Insufficient␣funds" let () = let w1 = make_withdraw (ref 100) and w2 = make_withdraw (ref 100) in print_result (w1 10); (* Ok (90) *) print_result (w1 20); (* Ok (70) *) print_result (w1 80); (* Err(" Insufficient funds ") * print_result (w2 40) (* Ok (60) *) 5 / 22 -
▶ Rust ͷ߹ fn make_withdraw(mut balance: i32) -> Box <FnMut(i32)
-> Result <i32 , &’static str >> { Box::new(move |amount: i32| { if balance >= amount { balance -= amount; Ok(balance) } else { Err("Insufficient␣funds") } }) } let mut w1 = make_withdraw (100); let mut w2 = make_withdraw (100); println !("{:?}", w1 (10)); // Ok (90) println !("{:?}", w1 (20)); // Ok (70) println !("{:?}", w1 (80)); // Err(" Insufficient funds ") println !("{:?}", w2 (40)); // Ok (60) 6 / 22 -
▶ ؆୯ͳؔΛฦͯ͠ΈΔ fn id_i32 () -> i32 -> i32 {
|x: i32| { x } } ▶ ΤϥʔʹͳΔ error: expected one of ‘!‘, ‘(‘, ‘::‘, ‘<‘, ‘where‘, or ‘{‘, found ‘->‘ --> account1.rs:2:24 | 2 | fn id_i32() -> i32 -> i32 { | ^^ ▶ ??? 8 / 22 -
▶ υΩϡϝϯτΛಡΉͱɺΫϩʔδϟͷܕ Fn ͱ͍͏ trait Λ ࣮͍ͯ͠ͳ͍ͱ͍͚ͳ͍Β͍͠ ▶ ͳΜ͔Τϥʔϝοηʔδෆͳؾ͕ ▶
ͱΓ͋͑ͣงғؾͰԼͷΑ͏ʹॻ͍ͯΈΔ fn id_i32 () -> Fn(i32) -> i32 { |x: i32| { x } } ▶ ΤϥʔʹͳΔ error[E0308]: mismatched types --> account1.rs:7:9 | 7 | |x: i32| { x } | ^^^^^^^^^^^^^^ expected trait std::ops::Fn, found closure | = note: expected type ‘std::ops::Fn(i32) -> i32 + ’static‘ = note: found type ‘[[email protected]:7:9: 7:23]‘ ▶ ??? 9 / 22 -
▶ ΫϩʔδϟͷܕͦΕͧΕݻ༗ͷܕ໊͕ͭͨ͘Ίɺγάχ νϟͷܕͱਪ͞ΕͨܕͱͰϛεϚον͕ى͖͍ͯΔͱࢥΘ ΕΔ ▶ ྫ͑ɺҾͱͯ͠ΫϩʔδϟΛड͚औΔͱ͖ɺ generics ʹ trait ੍Λ͚ͭΔܗͰܕΛॻ͔ͳ͍ͱ͍͚
ͳ͍ ▶ > Because each closure generates its own environment struct and implementation of Fn and friends, these types are anonymous. They exist solely for this closure. So Rust shows them as closure@<anon>, rather than some autogenerated name. ▶ ΫϩʔδϟΛฦ͍ͨ͠߹Ͳ͏ͨ͠Β͍͍͔͔Βͣ... 10 / 22 -
▶ ࣮͏ҰͭΤϥʔ͕ग़͍ͯͨͷͰͦͪΒʹͯ͠ΈΔ error[E0277]: the trait bound ‘std::ops::Fn(i32) -> i32 +
’static: std::marker::Sized‘ is not satisfied --> account1.rs:6:20 | 6 | fn id_i32() -> Fn(i32) -> i32{ | ^^^^^^^^^^^^^^ | the trait ‘std::marker::Sized‘ is not implemented for | ‘std::ops::Fn(i32) -> i32 + ’static‘ | = note: ‘std::ops::Fn(i32) -> i32 + ’static‘ does not have a constant size known at compile-time = note: the return type of a function must have a statically known size ▶ Fn(i32) -> i32 trait ͳͷͰɺෳͷܕͷީิ͕͋Γɺ ܕͷαΠζ͕͔Βͳ͍ ▶ ฦΓͷܕͷαΠζίϯύΠϧ࣌ʹ͔͍ͬͯΔඞཁ͕͋ ΔͨΊɺౖΒΕ͍ͯΔ 11 / 22 -
▶ Box Λ͏ ▶ ώʔϓྖҬͷϙΠϯλܕ ▶ ࢀরͳͷͰܕͷαΠζҰఆ fn id_i32 ()
-> Box <Fn(i32) -> i32 > { Box::new(|x: i32| { x }) } ▶ Ͱ͖ͨ! ▶ ͳ͔ͥܕνΣ οΫ௨Δ 12 / 22 -
▶ ͦΖͦΖ mut ͍ͨ͠ ▶ Rust ͷมجຊ immutableɺՄมʹ͍ͨ͠ͱ͖ mut Λ͚ͭΔ
fn make_adder () -> Box <Fn(i32) -> i32 > { let mut acc = 0; Box::new(|x: i32| { acc += x; acc }) } 13 / 22 -
▶ ΤϥʔʹͳΔ error[E0373]: closure may outlive the current function, but
it borrows ‘acc‘, which is owned by the current function --> account1.rs:16:18 | 16 | Box::new(|x: i32| { | ^^^^^^^^ may outlive borrowed value ‘acc‘ 17 | acc += x; | --- ‘acc‘ is borrowed here | ▶ ΦΞΞΞΞΞΞΞ 14 / 22 -
▶ ߟ͑ͯΈΑ͏ fn make_adder () -> Box <Fn(i32) -> i32
> { let mut acc = 0; Box::new(|x: i32| { acc += x; acc }) } let mut adder = make_adder () println !("{:?}", adder (10)) ▶ acc ͷ lifetime make_adder ͷத͚ͩ ▶ make_adder ͷฦ͢Ϋϩʔδϟ make_adder ͷຊମΑΓ ੜ͖͢Δ ▶ make_adder ͷฦ͢Ϋϩʔδϟ acc Λࢀর͍ͯ͠Δ͕ make_adder ͷ࣮ߦ͕ऴΘͬͨ͋ͱͩͱ͢Ͱʹ acc ࢮΜͰ ͍ΔͨΊࢀরͰ͖ͳ͍ 15 / 22 -
help: to force the closure to take ownership of ‘acc‘
(and any other referenced variables), use the ‘move‘ keyword, as shown: | Box::new(move |x: i32| { ▶ ࣮ help ͕ग़͍ͯͨͷͰɺͦΕʹै͍ move Λ͏ ▶ move Λ͏ͱڥதͷมͷॴ༗ݖΛऔಘ͢Δ ▶ Ϋϩʔδϟʹ৽͘͠ڥΛ༩͑Δͱߟ͑ΒΕΔ ▶ ڥͷ࡞Λ໌ࣔ͢Δඞཁ͕͋Δ fn make_adder () -> Box <Fn(i32) -> i32 > { let mut acc = 0; Box::new(move |x: i32| { acc += x; acc }) } ▶ acc ͷॴ༗ݖ͕ΫϩʔδϟͷதʹҠৡ͞ΕΔͷͰɺΫϩʔ δϟͱ acc ͷ lifetime ͕Ұக͢Δ 16 / 22 -
▶ ͱ͜ΖͰΤϥʔͰ͢ error: cannot assign to captured outer variable in
an ‘Fn‘ closure --> account1.rs:25:13 | 25 | acc += x; | ^^^^^^^^ | 17 / 22 -
fn make_adder () -> Box <Fn(i32) -> i32 > {
let mut acc = 0; Box::new(move |x: i32| { acc += x; acc }) } ▶ Fn ͱ͍͏ trait ڥதͷมΛมߋ͢Δ͜ͱ͕Ͱ͖ͳ͍ ▶ มߋ͍ͨ͠߹ FnMut Λ͏ඞཁ͕͋Δ 18 / 22 -
Fn ʹ͍ͭͯগ͠ৄࡉ ▶ Fn ͱ͍͏ trait ʮ࣮ߦ͢Δʯͱ͍͏ϝιουΛ࣮͢Δ͜ ͱΛཁٻ͍ͯ͠Δ pub trait
Fn <Args > : FnMut <Args > { extern "rust -call" fn call (&self , args: Args) -> Self :: Output; } ▶ &self ͱͯ͠ΫϩʔδϟຊମΛड͚औ͍ͬͯΔ͜ͱʹҙ ▶ ͨͩͷࢀরͳͷͰɺมߋͰ͖ͳ͍ ▶ FnMut ͷ߹ɺ&mut self ͱͯ͠ΫϩʔδϟΛड͚औͬͯ ͍ΔͨΊɺڥΛมߋ͢Δ͜ͱ͕Մೳ pub trait FnMut <Args > : FnOnce <Args > { extern "rust -call" fn call_mut (&mut self , args: Args) -> Self :: Output; } 19 / 22 -
▶ ॳظͦͷ··ड͚औΔ ▶ make_adder ͷฦΓ mut Ͱͳ͍ͱ͍͚ͳ͍͜ͱʹҙ fn make_adder(init: i32)
-> Box <FnMut(i32) -> i32 > { let mut acc = init; Box::new(move |x: i32| { acc += x; acc }) } let mut adder = make_adder (10); println !("{:?}", adder (10)); 20 / 22 -
▶ ͱ͍͏Θ͚Ͱʢ࠶ܝʣ fn make_withdraw(mut balance: i32) -> Box <FnMut(i32) ->
Result <i32 , &’static str >> { Box::new(move |amount: i32| { if balance >= amount { balance -= amount; Ok(balance) } else { Err("Insufficient␣funds") } }) } let mut w1 = make_withdraw (100); let mut w2 = make_withdraw (100); println !("{:?}", w1 (10)); // Ok (90) println !("{:?}", w1 (20)); // Ok (70) println !("{:?}", w1 (80)); // Err(" Insufficient funds ") println !("{:?}", w2 (40)); // Ok (60) 21 / 22 -
ײ ▶ Ϋϩʔδϟ+mut ͷ߹ΘٕͤͰϋϚΓͲ͜Ζ͕͔ͳΓ૿͑ͨ ҹ ▶ ࢀߟʹ͢Δͷ The Rust Programming
Language ͚ͩͰ ཧղͰ͖Δ ▶ help ศར͚ͩͲͪΌΜͱߟ͑ͨ΄͏͕͍͍ ▶ ͦͷ΄͏͕໘ന͍ 22 / 22