Как вернуть функцию из функции с целью ввода параметров?

#rust

Вопрос:

Я пытаюсь вернуть функцию из другой функции.

 // Immediately run function passed in
fn set_timeout(f: amp;dyn Fn()) {
    f();
}

fn callback() -> dyn Fn() {
    return fn() {
        println!("hi");
    };
}

fn main() {
  set_timeout(amp;callback());
}
 

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

 fn main() {
  let fooRef = Arc::new(Mutex::new(String::from("foo")));
  let fooRef1 = fooRef.clone();

  set_timeout(amp;(move || {
    let mut foo = fooRef1.lock().unwrap();
    foo.push_str("bar");
    println!("{}", foo);
  }));
}
 

Почему встроенное закрытие обратного вызова работает, а разделенная функция-нет?

РЕДАКТИРОВАТЬ: Вот сообщения об ошибках от rustc, полученные с помощью Rust playground.

    Compiling playground v0.0.1 (/playground)
error: expected one of `.`, `;`, `?`, `}`, or an operator, found keyword `fn`
 --> src/main.rs:7:12
  |
7 |     return fn() {
  |            ^^ expected one of `.`, `;`, `?`, `}`, or an operator

error[E0746]: return type cannot have an unboxed trait object
 --> src/main.rs:6:18
  |
6 | fn callback() -> dyn Fn() {
  |                  ^^^^^^^^ doesn't have a size known at compile-time
  |
  = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
  = note: if all the returned values were of the same type you could use `impl Fn()` as the return type
  = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
  = note: you can create a new `enum` with a variant for each returned type
help: return a boxed trait object instead
  |
6 | fn callback() -> Box<dyn Fn()> {
7 |     Box::new(return fn() {
8 |         println!("hi");
9 |     };)
  |

error[E0277]: the size for values of type `(dyn Fn()   'static)` cannot be known at compilation time
  --> src/main.rs:13:16
   |
13 |   set_timeout(amp;callback());
   |                ^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `(dyn Fn()   'static)`
   = note: the return type of a function must have a statically known size

Some errors have detailed explanations: E0277, E0746.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `playground` due to 3 previous errors
 

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

1. Пожалуйста, укажите ошибки, которые вы видите. Они, вероятно, будут проливать свет.

2. В то же время, один из них, скорее всего, именно то, что вам нужно, в зависимости от ваших требований: play.rust-lang.org/…

3. Обратите внимание, что fn и Fn они очень разные. fn является указателем функции (типом) и относится к статическим функциям, которые не захватывают их среду. Fn является особенностью и может быть реализована как замыканиями, так и статическими функциями.

Ответ №1:

Итак, глядя на ошибки rustc, первая проблема заключается в том, что return ожидается нечто иное, чем объявление функции. Вместо этого, как указано в комментарии @peter-hall, вы должны сначала определить функцию, а затем просто использовать ее в качестве возвращаемого значения:

 def outer() -> fn() {
  fn inner() {
    //blabla
  }
  inner
}
 

А затем возникают следующие проблемы dyn , и вы не можете просто вернуть голый dyn объект.

Одно из решений этой проблемы указано компилятором: поместите свой объект признака в a Box , т. е. выделите его в куче.

В качестве альтернативы используйте impl Trait синтаксис: https://doc.rust-lang.org/rust-by-example/trait/impl_trait.html

Или просто укажите, что ваш тип возврата-это тип fn . Следует отдать должное всем этим предложениям peter-hall .