Почему я могу написать тип функции в параметре типа структуры?

Если я правильно понимаю, в 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;
}

* это не столько неявное приведение, сколько неявное определение типа

Другие вопросы по тегам