2014-11-09 1 views
1

По названию. Ты можешь? Или это требует промежуточного шага для листинга признаков?Можете ли вы принудить некоторых (box |: |) к опции <Box <FnOnce<...> >> в ржавчине?

Я понимаю, что реформа закрытия еще не завершена, и с ней появляется множество открытых ошибок.

Тем не менее, трекер ошибок настолько полно ошибок и RFC, и ссылки на устаревшие и новые билеты, мне очень тяжело, пытаясь понять состояние игры с новыми распакованными замыканиями в ржавчине.

Это работает:

#![feature(unboxed_closures, unboxed_closure_sugar)] 
#![allow(dead_code, unused_variables)] 

fn test(bar:Box<FnOnce<(int,),()> + Send>) { 
    bar.call_once((10,)); 
} 

fn main() { 
    let bar:Box<FnOnce<(int,),()> + Send> = box |:x:int| { println!("Hi:{}", x); }; 
    test(bar); 

    test(box |:x:int| { println!("Hi:{}", x); }); 
} 

и это работает:

#![feature(unboxed_closures, unboxed_closure_sugar)] 
#![allow(dead_code, unused_variables)] 

fn test2(mut bar:Option<Box<FnOnce<(int,),()> + Send>>) { 
    bar.take().unwrap().call_once((10,)); 
} 

fn main() { 
    let bar2:Box<FnOnce<(int,),()> + Send> = box |:x:int| { println!("Hi:{}", x); }; 
    test2(Some(bar2)); 
} 

Однако, это не работает по какой-то причине:

#![feature(unboxed_closures, unboxed_closure_sugar)] 
#![allow(dead_code, unused_variables)] 

fn test2(mut bar:Option<Box<FnOnce<(int,),()> + Send>>) { 
    bar.take().unwrap().call_once((10,)); 
} 

fn main() { 
    test2(Some(box |:x:int| { println!("Hi:{}", x); })); 
} 

Ошибка:

foo.rs:21:9: 21:53 error: mismatched types: expected `core::option::Option<Box<core::ops::FnOnce<(int,),()>+Send>>`, found `core::option::Option<Box<closure>>` (expected trait core::ops::FnOnce, found closure) 
foo.rs:21 test2(Some(box |:x:int| { println!("Hi:{}", x); })); 

Итак, вопрос:

1) Должно ли вышеуказанный код работать? Или Option<>/Some() подразумевает что-то сложное, чего я не понял в этом контексте?

2) Если да, есть ли открытый билет для неявных преобразований между сахаром |:| и FnOnce?

(потому что https://github.com/rust-lang/rust/issues/18101, похоже, предполагает, что это должно быть сделано, поэтому пример № 1 работает, но я полностью потерялся, пытаясь найти эту мета-ошибку, чтобы найти какую-то конкретную ошибку, относящуюся к закрытию сахара).

ответ

5

Стоит отметить, что это является общим свойством объектов признака и родовых структур/перечислений, и вовсе не специфичны для Unboxed закрытия, FnOnce, Option или |:| (особенно не это, так как это просто хороший способ для создания значения, реализующего определенный признак).

Кроме того, недавний RFC#401 связан.

1) Should the above code work? Or does Option<>/Some() imply something complex that I haven't understood in this context?

Box<FnOnce<..>> является объектом черта, и поэтому не имеет одинаковое представление или типа как нединамический Box<F> для F: FnOnce<...>. Теоретически мы могли бы поддерживать более глубокие принуждения посредством перечислений и структур для некоторых типов, но это не обязательно хорошо играло бы/равномерно с совпадением и противоречием.

В любом случае, вы можете сделать нормальный объект черта ролях:

#![feature(unboxed_closures, unboxed_closure_sugar)] 
#![allow(dead_code, unused_variables)] 

fn test2(mut bar:Option<Box<FnOnce<(int,),()> + Send>>) { 
    bar.take().unwrap().call_once((10,)); 
} 

fn main() { 
    test2(Some((box |: x| println!("Hi:{}", x)) as Box<FnOnce(int)+Send>)); 
} 

На замечание о дисперсии, рассмотрим:

enum Option2<T> { 
    Empty, 
    One(fn() -> T) 
} 

То есть, либо хранит ничего, либо запоминает функция, которая возвращает T. Что означает лить Option2<Box<X>> в Option2<Box<Trait>>?Нельзя просто принудительно притворяться, что возвращаемая функция Box<X> возвращает значение типа Box<Trait>.

2) If so, is there an open ticket for implicit conversions between the |:| sugar and FnOnce types?

|:| сахар типа FnOnce -implementing. FnOnce - это черта и принуждения, как любой другой объект-объект.

+0

На самом деле невозможно принудительно использовать 'FnOnce' (то есть использовать' FnOnce' как объект-объект), поскольку 'FnOnce' не является объектно-безопасным (метод' call_once' принимает значение 'self' by-value) , Нынешним обходным путем является использование 'std :: thunk :: Invoke' как объекта-объекта и вызов метода 'invoke()', который принимает значение self как 'Box ', так что это безопасно для объекта. Подробнее в [этом сообщении блога] (http://smallcultfollowing.com/babysteps/blog/2014/11/26/purging-proc/). – Vaelden

+0

@ Vaelden, это очень верно, однако этот ответ был написан до того, как безопасность объектов была вещью (что означает «Box ' -> 'Box ' было законным), и в любом случае описанная проблема по-прежнему является проблемой с объектов. – huon

Смежные вопросы