Есть ли способ выразить «один и тот же» универсальный тип с другой границей времени жизни? - PullRequest
0 голосов
/ 20 сентября 2018

Рассмотрим следующую (неполную) сигнатуру функции:

unsafe fn foo<'a, T: 'a>(func: impl FnOnce() -> T + 'a) -> ...

Есть ли способ (конечно, небезопасно) transmute функции ввода, чтобы она стала impl FnOnce() -> S + 'static где S - тот же тип, что и T, но с S: 'static.

Я знаю, что можно трансмутировать границы времени жизни для самого замыкания, используя черту в штучной упаковке (FnBox) и затем вызывая transmute onкоробка.Однако это не влияет на тип возвращаемого значения (T).Насколько я понимаю, T: 'a и T: 'static - это разные типы в системе типов.Поэтому мне интересно, возможно ли вообще выразить это в Rust.

Полагаю, подпись должна выглядеть следующим образом (игнорируя границы времени жизни для самого замыкания):

unsafe fn<'a, T, S>(func: impl FnOnce() -> T) -> impl FnOnce() -> S
where
    T: 'a,
    S: 'static`

но тогда как вы вызываете эту функцию без указания, что T и S идентичны, за исключением их срока жизни.

Отказ от ответственности Я знаю, что возиться с границами времени жизни обычноплохая идея, однако это для порождающих потоков, где ограничения времени жизни применяются другими способами.

1 Ответ

0 голосов
/ 20 сентября 2018

Если бы вы просто хотели сделать это с простыми типами, это было бы просто, но есть ряд препятствий для того, что вы пытаетесь.Я объясню их в том порядке, в котором я столкнулся с ними при попытке найти ответ.

Во-первых, вы не можете реализовать это с типами 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)
}

Таким образом, возможно, вам следует сделать шаг назад и найти другую проблему для решения вместо этой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...