Rust: проблема с созданием структуры заводским методом

#rust

#Ржавчина

Вопрос:

возьмите это минимальное воспроизведение (игровая площадка), где я пытаюсь создать структуру с замыканием в виде поля и определить некоторые дополнительные фабричные методы, которые предоставляют пользовательскую логику в форме замыкания.

 #![allow(non_snake_case)]

struct FunStruct<T>
where
    T: Fn(i32) -> i32
{
    pub p: T,
}

fn Create<T>() -> FunStruct<T>
where
    T: Fn(i32) -> i32
{
    let p : T = |val| -> i32 {
        return val;
    };
    
    let a = FunStruct {
        p,
    };
    
    return a;
}

fn main() {
    let a = Create();
    
    println!("{}", (a.p)(5));
}
  

приведенный выше фрагмент выдает следующую ошибку.

 error[E0308]: mismatched types
  --> src/main.rs:14:17
   |
10 |   fn Create<T>() -> FunStruct<T>
   |             - this type parameter
...
14 |       let p : T = |val| -> i32 {
   |  _____________-___^
   | |             |
   | |             expected due to this
15 | |         return val;
16 | |     };
   | |_____^ expected type parameter `T`, found closure
   |
   = note: expected type parameter `T`
                     found closure `[closure@src/main.rs:14:17: 16:6]`

error[E0282]: type annotations needed for `FunStruct<T>`
  --> src/main.rs:26:13
   |
26 |     let a = Create();
   |         -   ^^^^^^ cannot infer type for type parameter `T` declared on the function `Create`
   |         |
   |         consider giving `a` the explicit type `FunStruct<T>`, where the type parameter `T` is specified
   |
   = note: type must be known at this point

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0282, E0308.
For more information about an error, try `rustc --explain E0282`.
  

однако, похоже, это работает просто отлично

 struct FunStruct<T>
where
    T: Fn(i32) -> i32
{
    pub p: T,
}

fn main() {
    let p = |val| -> i32 {
        return val;
    };
    
    let a = FunStruct {
        p
    };
    
    println!("{}", (a.p)(5));
}
  

кажется, что один уровень абстракции разрушает его.

Комментарии:

1. Вы можете взглянуть на doc.rust-lang.org/book /. … Похоже, «Rust не знает, сколько места потребуется для хранения закрытия» (что немного странно, потому что у компилятора, похоже, много информации о закрытии), поэтому его нужно хранить в куче.

2. @ForceBru я не возвращаю closoure , хотя и предоставляю всю необходимую компилятору информацию о размерах. на самом деле, я даю больше информации в примере, который не компилируется, чем в примере, который компилируется.

Ответ №1:

Общий параметр означает, что он работает для любого типа — однако замыкание в Create не работает для любого типа замыкания, оно создает замыкание с одним конкретным типом. Вы можете сделать это:

 fn Create() -> FunStruct<impl Fn(i32) -> i32>{
    let p/*: some anonymous, unique type */ = |val| -> i32 {
        return val;
    };
    
    let a = FunStruct {
        p,
    };
    
    return a;
}
  

Позиция impl Trait in return означает «Я возвращаю некоторый тип, который реализует эту особенность, я не собираюсь рассказывать вам, что это на самом деле». В отличие от этого, ваша исходная функция говорит: «Учитывая любой тип, который является функцией, я могу его вернуть», что, очевидно, не имеет смысла.