Разное поведение онлайн и офлайн компиляторов

41 views
Skip to first unread message

Mike Potanin

unread,
Nov 25, 2014, 8:25:34 AM11/25/14
to rust-r...@googlegroups.com

Добрый день!
Пробую unboxed_closures на онлайн компиляторе - работает до версии 11.0
http://is.gd/pTwnqk

А то же самое на свежеоткомпилированном у себя на машине выдает:

pm@pm:~/lang/rust/test$ rustc adder.rs
adder.rs:3:32: 3:33 error: expected type, found token Colon
adder.rs:3 fn make_adder(n: int) -> Box<|&: int| -> int> {
                                                             ^

pm@pm:~/lang/rust/test$ rustc --version
rustc 0.13.0-dev (0c1d853fb 2014-11-25 06:51:38 +0000)

Других версий компилятора на машине нет.

Может опция нужна, что бы он feature воспринял?

Vladimir Matveev

unread,
Nov 25, 2014, 8:42:53 AM11/25/14
to Mike Potanin, rust-r...@googlegroups.com
Добрый день!

Я давно заметил, что онлайн-компилятор как-то странно обновляется. Судя по всему, там довольно старая версия.

Синтаксис unboxed-замыканий, который вы используете, устарел. Теперь нужно так:

#![feature(unboxed_closures)]

fn make_adder(n: int) -> Box<Fn(int) -> int + 'static> {
box move |i| i+n
}

fn ad(f: &Box<Fn(int) -> int + 'static>, i: int) -> int {
f.call((i,))
}

fn main() {
let f = make_adder(4);
println!("{}", ad(&f, 13));
println!("{}", f.call((15,)));
}


Однако это работать не будет до тех пор, пока не вмёржат пулл-реквест [1] (засабмичен 2 часа назад :)), меняющий приоритет оператора `+` в грамматике типов. До этого придётся писать так:

#![feature(unboxed_closures)]

fn make_adder(n: int) -> Box<Fn<(int,), int> + 'static> {
box move |i| i+n
}

fn ad(f: &Box<Fn<(int,), int> + 'static>, i: int) -> int {
f.call((i,))
}

fn main() {
let f = make_adder(4);
println!("{}", ad(&f, 13));
println!("{}", f.call((15,)));
}

Кстати, буквально пару дней назад синтаксис создания unboxed-замыканий унифицировали со старыми замыканиями, так что теперь необязательно писать `|&: i: int|`, достаточно просто `|i|` (но `move` всё-таки нужно). В скором времени, я думаю, сделают и так, чтобы можно было вызывать замыкания через Deref, т.е. можно будет выкинуть ещё и явный вызов `call()`, такое ишью тоже висит.


[1]: https://github.com/rust-lang/rust/pull/19298
> --
> Вы получили это сообщение, поскольку подписаны на группу "Rust по-русски".
> Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес rust-russian...@googlegroups.com.
> Чтобы посмотреть обсуждение на веб-странице, перейдите по ссылке https://groups.google.com/d/msgid/rust-russian/c478a7da-9d18-451e-8c6c-34298738d96f%40googlegroups.com.
> Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

Mike Potanin

unread,
Nov 25, 2014, 9:01:25 AM11/25/14
to rust-r...@googlegroups.com

Thanks!

Правда, не понятно, что значит 'static - там вроде все динамически аллокируется...

Vladimir Matveev

unread,
Nov 25, 2014, 10:54:29 AM11/25/14
to Mike Potanin, rust-r...@googlegroups.com
Всё очень просто. `Box<T>` - это trait object, если `T` - это трейт. Трейты могут быть реализованы разными типами, в том числе такими, у которых внутри есть ссылки:

struct WithoutReference { value: int }
struct WithReference<'a> { value: &'a int }

trait GetInt { fn get_int(&self) -> int }

impl GetInt for WithoutReference {
fn get_int(&self) -> int { self.value }
}

impl<‘a> GetInt for WithReference<‘a> {
fn get_int(&self) -> int { *self.value }
}

Поскольку вы не можете контролировать, кто реализует трейт (любой публичный трейт можно реализовать для «своего» типа), то вы обязаны при объявлении типа trait object’а учитывать, что внутри него могут быть ссылки. Таким образом, `'a` в `Box<Trait + 'a>` - это как раз наименьшее из времён жизни всех ссылок, потенциально содержащихся внутри объекта.

`'static`, как следствие, означает, что внутри объекта не будет ссылок со временем жизни меньшим, чем время жизни всей программы. В большинстве случаев для замыканий, содержащихся внутри Box’ов, этого вполне достаточно.
> --
> Вы получили это сообщение, поскольку подписаны на группу "Rust по-русски".
> Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес rust-russian...@googlegroups.com.
> Чтобы посмотреть обсуждение на веб-странице, перейдите по ссылке https://groups.google.com/d/msgid/rust-russian/cd187fa9-06b3-4649-b91c-229dbb18dfbf%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages