generics - 有没有办法表达具有不同生命周期界限的 "same"泛型类型?

标签 generics rust lifetime type-constraints

考虑以下(不完整)函数签名:

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

有没有办法(当然不安全)transmute输入函数,使其变为 impl FnOnce() -> S + 'static其中 S 与 T 类型相同,但带有 S: 'static .

我知道可以通过使用盒装特征( FnBox )然后在盒子上调用 transmute 来改变闭包本身的生命周期界限。但是,这不会影响返回类型( T )。据我了解,T: 'aT: 'static就类型系统而言,它们是不同的类型。所以我想知道是否可以用 Rust 来表达这一点。

我想签名必须看起来像这样(忽略闭包本身的生命周期界限):

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

但是如果没有 T 的规范,你如何调用这个函数呢?和S除了生命周期之外,其他都是相同的。

免责声明 我知道修改生命周期界限通常是一个坏主意,但这适用于通过其他方式强制执行生命周期限制的生成线程。

最佳答案

如果您只想使用简单类型来执行此操作,这将很简单,但是您尝试的操作会遇到许多障碍。我将按照我在尝试寻找答案时遇到的顺序来解释它们。

首先,你不能用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 升级至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)
}

总之,也许您应该退后一步,找到一个不同的问题来解决,而不是这个问题。

关于generics - 有没有办法表达具有不同生命周期界限的 "same"泛型类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52424449/

相关文章:

java - 在 HashSet 中搜索

java - 使用泛型在方法调用时从父级转换为子级

rust - 从parking_lot::RwLock返回映射的数据

尝试改变返回迭代器的闭包内的状态时出现 Rust 错误 "cannot infer an appropriate lifetime for borrow expression"

rust - 如何解决 "indicate anonymous lifetime <' _>”错误?

java - 在也实现相同类的基类中使用泛型的好处

c# - 使用具体类型覆盖通用方法(类型参数 * 隐藏类 *)

vector - 从 Rust 中的向量构建 HashSet

rust - 为什么胖指针有时会向外渗透?

rust - 包装函数返回迭代器时的生命周期问题