考虑以下(不完整的)函数签名:
unsafe fn foo<'a, T: 'a>(func: impl FnOnce() -> T + 'a) -> ...
有没有一种方法(当然是不安全地)transmute
的输入函数,因此它变成impl FnOnce() -> S + 'static
,其中S与T的类型相同,但带有S: 'static
。
我知道可以通过使用带框特征(FnBox
)然后在框上调用transmute来改变封闭本身的生命周期界限。但是,这不会影响返回类型(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
除了生命周期相同的情况下调用此函数。
免责声明 我知道,修改生命周期界限通常不是一个好主意,但是,这是为了生成通过其他方式强制执行生命周期限制的线程。
答案 0 :(得分:2)
如果您只想使用简单的类型来做到这一点,那将很简单,但是您要尝试的操作有很多障碍。在尝试寻找答案时,我会按照遇到它们的顺序来解释它们。
首先,您不能使用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()>
,但它是currently impossible to call that function later,这意味着您必须做出另一个妥协,即从FnOnce
升级到{{1} }。
Fn
总而言之,也许您应该退后一步,找到另一个要解决的问题,而不是这个问题。