Почему я могу написать тип функции в параметре типа структуры?
Если я правильно понимаю, в Rust каждый тип замыкания имеет уникальный тип, который нельзя выписать. Я также думал, что это применимо к функциям, однако я могу сделать следующее, в котором я явно записываю параметр типа в возвращаемые типы
get_struct_1
а также
get_struct_2
:
struct FooStruct<F>
where F: Fn(i32) -> i32
{
f: F,
}
fn foo(x: i32) -> i32 {
2*x
}
fn bar(x: i32) -> i32 {
-1*x
}
fn get_struct_1() -> FooStruct<fn(i32) -> i32>
{
FooStruct { f: foo }
}
fn get_struct_2() -> FooStruct<fn(i32) -> i32>
{
FooStruct { f: bar }
}
// This does not work - the trait has to be boxed
//fn get_struct_3() -> FooStruct<Fn(i32) -> i32>
//{
// 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 FooStruct<fn(i32) -> i32>
//y = get_struct_1();
}
Я думал, что Rust был мономорфен в том, как он обрабатывает параметры типа. Так что если я сделаю это
struct FooStruct {
f: Box<dyn Fn(i32) -> i32>
}
программа будет динамически определять, какие
f
работать во время выполнения, но
FooStruct<F>
версия избегает динамической отправки.
Этот пример, кажется, с этим не согласен. Если
x = get_struct_2();
линии были внутри
if
оператор, компилятор не сможет определить,
x
содержал обернутую версию функции
foo
или
bar
.
1 ответ
Замыкания (и функции в этом отношении) действительно имеют уникальные, не записываемые типы. Однако их также можно привести (и неявно* тоже) к указателям на функции, если они не захватывают какие-либо переменные, чего нет у вас. По сути, это причина, по которой это работает:
fn main() {
// closure is inferred to be a function pointer
let mut f: fn() -> 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;
}
* это не столько неявное приведение, сколько неявное определение типа