#rust #closures #typing #monomorphism
Вопрос:
Если я правильно понимаю, в Rust каждый тип закрытия имеет уникальный тип, который не может быть записан. Я также думал, что это применимо к функциям, однако я могу сделать следующее, в котором я явно пишу параметр типа в возвращаемых типах get_struct_1
и get_struct_2
:
struct FooStructlt;Fgt; where F: Fn(i32) -gt; i32 { f: F, } fn foo(x: i32) -gt; i32 { 2*x } fn bar(x: i32) -gt; i32 { -1*x } fn get_struct_1() -gt; FooStructlt;fn(i32) -gt; i32gt; { FooStruct { f: foo } } fn get_struct_2() -gt; FooStructlt;fn(i32) -gt; i32gt; { FooStruct { f: bar } } // This does not work - the trait has to be boxed //fn get_struct_3() -gt; FooStructlt;Fn(i32) -gt; i32gt; //{ // FooStruct { f: |x| 10*x } //} fn main() { let mut x = get_struct_1(); // Why does this work - do bar and foo have the same type? x = get_struct_2(); // Why does this work - doesn't a closure have its own unique, unwriteable type? x = FooStruct { f: |x| 10*x }; let mut y = FooStruct { f: |x| 10*x }; // Does not work - no two closures have the same type. //y = FooStruct { f: |x| 10*x }; // Does not work - even though the 'other way around' worked with x. // But _does_ work if I type-annotate y with FooStructlt;fn(i32) -gt; i32gt; //y = get_struct_1(); }
Я думал, что Rust мономорфен в том, как он обрабатывает параметры типа. Так что, если я сделаю это
struct FooStruct { f: Boxlt;dyn Fn(i32) -gt; i32gt; }
программа будет динамически определять, что f
запускать во время выполнения, но FooStructlt;Fgt;
версия позволяет избежать динамической отправки.
Этот пример, по-видимому, не согласен с этим. Если x = get_struct_2();
бы строка находилась внутри if
инструкции, компилятор не смог бы определить x
, содержит ли она обернутую версию функции foo
или bar
.
Ответ №1:
Замыкания (и функции, если на то пошло) действительно имеют уникальные, неписаные типы. Однако они также могут быть применены (и неявно* тоже) к указателям функций, когда они не захватывают никаких переменных, чего не делают ваши. По сути, именно по этой причине это работает:
fn main() { // closure is inferred to be a function pointer let mut f: fn() -gt; i32 = || 5; // assigning a different function pointer f = || 6; }
Но это не так:
fn main() { // closure is inferred to be a unique closure type let mut f = || 5; // uh oh! different closure type, errors f = || 6; }
* это не столько неявное приведение, сколько неявный вывод типа
Комментарии:
1. Хорошо, это немного помогает. Но означает ли это, что в вашем первом примере динамическая отправка происходит при
f
вызове?2. Не совсем.
f
сохраняет указатель на функцию, на что бы она ни указывала, вызывается при вызовеf
. Вы могли бы сказать, что это динамическая отправка в том смысле, что то, на чтоf
указывает, может измениться, но при этом не задействованы переменные, как при работе сdyn Trait