代码之家  ›  专栏  ›  技术社区  ›  Earth Engine

如何为函数指针参数指定泛型生存期?

  •  1
  • Earth Engine  · 技术社区  · 6 年前

    背景

    Rust中的闭包具有匿名类型,不能称为已知的具体类型。然而 from Feb 2017 ,所有非捕获闭包都可以转换为匿名函数,并且具有与函数指针相同的类型。

    我想创建一个标准化curried闭包的类型。如果我们有一个函数 fn(T1, T2, ...) -> R 我们可以有一种特殊的类型 FnXXX(T2, ...) -> R (替换 XXX 具有 Mut Once ,或 Box ). 然后可以在容器内使用它们,而不涉及动态调度。

    尝试 FnOnce

    以下工作:

    #![feature(unboxed_closures)]
    #![feature(fn_traits)]
    
    struct Curry0<T, R> {
        f: fn(T) -> R,
        v: T,
    }
    impl<T, R> FnOnce<()> for Curry0<T, R> {
        type Output = R;
        extern "rust-call" fn call_once(self, _: ()) -> R {
            (self.f)(self.v)
        }
    }
    
    fn curry<T, R>(f: fn(T) -> R, v: T) -> impl FnOnce() -> R {
        Curry0 { f: f, v: v }
    }
    
    fn main() {
        curry(|s| println!("{}", s), "Hello, World!")()
    }
    

    但是,我无法补充以下内容:

    impl<'a, T, R> FnMut<()> for Curry0<&'a mut T, R> {
        extern "rust-call" fn call_mut(&mut self, _: ()) -> R {
            (self.f)(self.v)
        }
    }
    

    错误消息:

    error[E0312]: lifetime of reference outlives lifetime of borrowed content...
      --> src/main.rs:16:18
       |
    16 |         (self.f)(self.v)
       |                  ^^^^^^
       |
    note: ...the reference is valid for the lifetime 'a as defined on the impl at 14:1...
      --> src/main.rs:14:1
       |
    14 | impl<'a, T, R> FnMut<()> for Curry0<&'a mut T, R> {
       | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the method body at 15:5
      --> src/main.rs:15:5
       |
    15 | /     extern "rust-call" fn call_mut(&mut self, _: ()) -> R {
    16 | |         (self.f)(self.v)
    17 | |     }
       | |_____^
    

    我的理解是,为了让它发挥作用, call_mut 一定要小心 &mut self 只为函数本身而活,如果 f 返回引用 v 的内部,它将是无效的。

    尝试 FnMut

    与…共事 FnMut公司 而不是 一次 上面我写道:

    #![feature(unboxed_closures)]
    #![feature(fn_traits)]
    
    struct Curry0Mut<'a, 'b, T, R>
    where
        T: 'a,
        R: 'b,
    {
        f: fn(&mut T) -> R,
        v: &'a mut T,
        _l: std::marker::PhantomData<&'b ()>,
    }
    impl<'a, 'b, T, R> FnOnce<()> for Curry0Mut<'a, 'b, T, R> {
        type Output = R;
        extern "rust-call" fn call_once(self, _: ()) -> R {
            (self.f)(self.v)
        }
    }
    impl<'a, 'b, T, R> FnMut<()> for Curry0Mut<'a, 'b, T, R>
    where
        T: 'a,
        R: 'b,
    {
        extern "rust-call" fn call_mut(&mut self, _: ()) -> R {
            (self.f)(self.v)
        }
    }
    
    fn curry<'a, T, R>(f: fn(&mut T) -> R, v: &'a mut T) -> impl FnMut() -> R + 'a {
        Curry0Mut {
            f: f,
            v: v,
            _l: std::marker::PhantomData,
        }
    }
    
    fn main() {
        let mut v = "Hello, World".to_owned();
        curry(|s| println!("{}", s), &mut v)();
    }
    

    这是更复杂的,不幸的是,我们有两个结构只是略有不同的用法。当我仔细观察我必须在这里做出的改变时,我发现 f级 实际上是其参数生存期内的泛型函数,并且 T 的一生与此无关。我们还要确保 R 不会比闭包本身的寿命长,因此它的生命周期必须在闭包内部进行编码。

    我暂时不谈细节 Fn 因为它是相似的。只需注意,这会使情况更糟,因为我们需要另一种 Curry0 ,因为 &mut T 不是 &T .

    问题

    有没有可能表达这样一个事实 有不同的人生期望 f级 s参数?

    例如,如何编写以下内容:

    struct Curry0<'a, 'b, T, R>
    where
        R: 'b,
    {
        f: fn(T) -> R, //T have generic lifetime
        v: T,          //T: 'a
        _a: std::marker::PhantomData<&'a ()>,
        _b: std::marker::PhantomData<&'b ()>,
    }
    
    0 回复  |  直到 6 年前