Если бы вы просто хотели сделать это с простыми типами, это было бы просто, но есть ряд препятствий для того, что вы пытаетесь.Я объясню их в том порядке, в котором я столкнулся с ними при попытке найти ответ.
Во-первых, вы не можете реализовать это с типами impl trait
, потому что сама функция должна выбирать конкретную реализацию, котораяон собирается вернуться, но не может, потому что реализация всегда будет основываться на выборе типа аргумента func
из вызывающей стороны.Это исключает «естественный» тип:
unsafe fn foo<'a, T>(func: impl FnOnce() -> T + 'a) -> impl FnOnce() -> T + 'static
и приводит к чему-то более похожему на:
unsafe fn foo<'a, T, F, G>(func: F) -> G
where
F: FnOnce() -> + 'a,
G: FnOnce() -> + 'static,
Но как вызывающая сторона узнает, какой тип G
должен быть?
Если вы попытаетесь использовать mem::transmute
, чтобы обмануть средство проверки заимствований, вам нужно будет указать, во что преобразовать.Проблема в том, что вы знаете только тип (например) impl FnOnce() -> T + 'static
, но на самом деле вы не можете записать конкретный тип замыкания, так что это тоже не сработает.
Я думаю, что ответ на Box
результат.Это может звучать неудовлетворительно, но становится еще хуже!Хотя можно создать Box<dyn FnOnce()>
, в настоящее время невозможно вызвать эту функцию позже , что означает, что вам нужно сделать еще один компромисс, то есть перейти с FnOnce
на Fn
.
use std::mem;
unsafe fn foo<'a, T>(func: impl Fn() -> T + 'a) -> Box<dyn Fn() -> T + 'static> {
let boxed: Box<dyn Fn() -> T + 'a> = Box::new(func);
mem::transmute(boxed)
}
Таким образом, возможно, вам следует сделать шаг назад и найти другую проблему для решения вместо этой.