Дважды вызвать один proc().

66 views
Skip to first unread message

Mike Potanin

unread,
Oct 13, 2014, 4:06:35 AM10/13/14
to rust-r...@googlegroups.com

Добрый день!
Есть код:
fn r(p:proc() -> int) -> (int,int) {
 (p(),p())
}

fn main() {
 println!("{}", r(proc () -> int { 1 }));
}

Он не компилируется со странной ошибкой:
p2.rs:3:7: 3:8 error: use of moved value: `p`
p2.rs:3  (p(),p())
              ^
p2.rs:3:3: 3:4 note: `p` moved here because it has type `proc() -> int`, which is non-copyable (perhaps you meant to use clone()?)
p2.rs:3  (p(),p())

Есть какой-нибудь способ вызвать одно замыкание несколько раз?

Владимир Матвеев

unread,
Oct 13, 2014, 4:17:17 AM10/13/14
to rust-r...@googlegroups.com
Нет, такого способа нет, потому что proc() - это такой вид замыкания, который может быть вызван только один раз. Если вам нужно вызвать замыкание много раз, то вам понадобится обычное замыкание: || -> int:

fn r(p: || -> int) -> (int, int) {
   
(p(), p())
}

Эти замыкания, однако, привязаны к текущему стекфрейму, поэтому их нельзя возвращать из функций. Сейчас в языке есть unboxed-замыкания, которые в итоге заменят || и proc(), но пока они немного бажные. Ваш пример с их использованием перепишется так:

#![feature(unboxed_closures, overloaded_calls)]

fn r
<F: FnMut() -> int>(mut p: F) -> (int, int) {
   
(p(), p())
}

fn main
() {
    println
!("{}", r(|&mut:| 1))
}


А возвращать такие замыкания можно, явно забоксив их в трейт-объект:

fn make_adder(i: int) -> Box<FnMut(int) -> int> {
    box
|&mut: j: int| i + j
}

Unboxed-замыкания, правда, немного бажные сейчас, но к версии 1.0 языка они должны полностью работать и заменить существующие замыкания.

Mike Potanin

unread,
Oct 13, 2014, 5:27:22 AM10/13/14
to rust-r...@googlegroups.com

 Thanks!
Только ночной сборкой не компилируется:
ub.rs:3:14: 3:15 error: expected `,`, found `(`
ub.rs:3 fn r<F: FnMut() -> int>(mut p: F) -> (int, int) {

Кстати, а без mut это переписать удастся?

Mike Potanin

unread,
Oct 13, 2014, 5:45:28 AM10/13/14
to rust-r...@googlegroups.com

Еще раз спасибо!
Так заработало:
#![feature(unboxed_closures, overloaded_calls)]

fn r<F: Fn<(),int>>(p: F) -> (int, int) {
    (p(), p())
}

fn main() {
    println!("{}", r(|&:| 1))
}

Владимир Матвеев

unread,
Oct 13, 2014, 5:58:25 AM10/13/14
to rust-r...@googlegroups.com
Да, если вы хотите гарантировать, что замыкание не меняет своего окружения, то вам нужен именно Fn. Однако FnMut более общий - с его помощью можно сделать всё, что можно сделать с помощью Fn, но не наоборот, поэтому я использовал его.

И кстати странно, что у вас ошибка компиляции. Я проверял программу в play.rust-lang.org, и там всё было нормально: вот с Fn, вот с FnMut. На play всегда стоит последняя ночная сборка, так что, вероятно, у вас версия всё же не последняя.

Mike Potanin

unread,
Oct 13, 2014, 6:15:34 AM10/13/14
to rust-r...@googlegroups.com
$ rustc --version
rustc 0.12.0-pre-nightly (325808a33 2014-09-08 20:51:14 +0000)

У меня хаскельная привычка - избегать mut любой ценой, надеюсь не придется от нее избавляться :-).

Владимир Матвеев

unread,
Oct 13, 2014, 6:24:49 AM10/13/14
to rust-r...@googlegroups.com
Ну вот, у вас версия месячной давности :) тогда, кажется, FnMut() -> int выглядел как |&mut:| -> int. Обновляйтесь почаще, для Rust это пока ещё очень актуально :)

Mike Potanin

unread,
Oct 13, 2014, 6:32:34 AM10/13/14
to rust-r...@googlegroups.com
git branch говорит, что master.
Или я чего-то недопонимаю...

Владимир Матвеев

unread,
Oct 13, 2014, 6:46:49 AM10/13/14
to rust-r...@googlegroups.com
Похоже на то, что у вас в PATH старая версия затесалась - в rustc --version выводится как раз timestamp момента сборки, как и хештег коммита. Сравните последний хеш в git log и в выводе rustc --version.

Я бы посоветовал не собирать компилятор вручную - это очень долго - а брать уже скомпиленный бинарник с официального сайта или из репозиториев/brew (если у вас линукс или мак, конечно).

Mike Potanin

unread,
Oct 13, 2014, 9:30:16 AM10/13/14
to rust-r...@googlegroups.com

Thanks!

Действительно, была старая версия в /usr/local.

Но пример с возвратом замыкания все равно не компилируется.
rc.rs:3:35: 3:36 error: expected `,`, found `(`
rc.rs:3 fn make_adder(i: int) -> Box<FnMut(int) -> int> {

Mike Potanin

unread,
Oct 13, 2014, 9:46:41 AM10/13/14
to rust-r...@googlegroups.com
Заработало только так:
#![feature(unboxed_closures, overloaded_calls, unboxed_closure_sugar)]

fn make_adder(i: int) -> Box<|&: int| -> int> {
    box |&: j: int| i + j
}

fn main() {
  let f = make_adder(1);
  println!("{}", f.call((2i,)));
}

Mike Potanin

unread,
Oct 13, 2014, 10:14:05 AM10/13/14
to rust-r...@googlegroups.com

Да, Unboxed-замыкания немножко сыроваты: http://is.gd/ZIIcPr
А очень их хочется... :-)
Reply all
Reply to author
Forward
0 new messages