#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
.