如何指定通过move传递给函数的泛型类型的生存期?

时间:2020-05-22 20:39:24

标签: generics rust lifetime

我想将一个函数包装在结构中以将其与其他数据打包在一起。当我明确指定函数的输入类型时,它可以正常工作。当我尝试将模式概括为通用结构时,会遇到生命周期错误。

我在操场上和下面共享了一个代码段。因为这是不能编译的。如果我从Wrapper切换到WrapperExplicit,则效果很好。怎么了我该如何使这种包装器具有通用性?

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=92cac14257aaec53b648df93566ac3df

use std::marker::PhantomData;

struct Reference<'a, X> {
    x : & 'a mut X 
}

//Works
struct WrapperExplicit<F> 
    where F : Fn(Reference<String>)
{
    data : u64,
    func : F,
}
impl<F> WrapperExplicit<F>
    where F : Fn(Reference<String>)
{
    pub fn new(func: F) -> WrapperExplicit<F> {
        WrapperExplicit {
            data : 10,
            func: func,
        }
    }

    pub fn call(& mut self, arg: Reference<String>)
    {
        (self.func)(arg)
    }
}

//Doesn't work
struct Wrapper<F, U> 
    where F : Fn(U)
{
    data : u64,
    func : F,
    _marker: PhantomData<U>,
}

impl<F,U> Wrapper<F,U>
    where F : Fn(U)
{
    pub fn new(func: F) -> Wrapper<F,U> {
        Wrapper {
            data : 0,
            func: func,
            _marker: PhantomData {}
        }
    }

    pub fn call(& mut self, arg: U)
    {
        (self.func)(arg)
    }
}

fn fn_borrow(x : Reference<String>) {
    println!("{}", x.x);
}

fn fn_move(y : String) {
    println!("{}", &y);
}

pub fn test_example() {
    let mut f = Wrapper::new(fn_borrow); //Doesn't work
    // let mut f = WrapperExplicit::new(fn_borrow); //Works
    let mut y = "Hello!".to_string();
    let x = Reference{ x : &mut y};
    f.call(x);
    fn_move(y);
    println!("{}", f.data)
}

编辑: 这是一个更简单的示例: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=0f4f5236d4e4439b3bec5a717f62567c

我认为问题在于,因为在创建结构时必须设置泛型类型,所以还要设置泛型的生存期,因此在调用结构的关联对象时不能使用不同的生存期功能。真的吗?有没有一种方法可以让结构的“类型”部分具有通用性,而让寿命在结构的一个功能被调用时确定呢?

use std::marker::PhantomData;

//Doesn't work
struct WrapperSimple<U> 
{
    data : u64,
    _marker: PhantomData<U>,
}

impl<U> WrapperSimple<U>
{
    pub fn new() -> WrapperSimple<U> {
        WrapperSimple {
            data : 0,
            _marker: PhantomData {}
        }
    }

    pub fn call(& mut self, _arg: U)
    {
    }
    pub fn call2<V>(& mut self, _arg: V)
    {
    }
}

fn fn_move(y : String) {
    println!("{}", &y);
}

fn main() {
    let mut w = WrapperSimple::<&str>::new();
    let mut y = "Hello!".to_string();
    let x = & mut y;
    w.call(x); //Doesn't work
    //w.call2(x); //Works, (obviously)
    fn_move(y);
    println!("{}", w.data)
}

编辑2:

我认为这是最终摆脱困境的方式:

  • 您不能在结构中存储具有泛型输入的泛型函数 而不在结构的类型中引用函数的输入类型 参数,因此也需要该类型的PhantomData字段 (否则,您将有一个不受约束或未使用的类型参数)
  • 一旦您拥有该类型的字段,该类型的嵌入式生存期即为 当结构被单态化时设置,例如 施工
  • 这意味着生命周期是固定的,并且每个生命周期都不能改变 当您调用该结构的方法之一
  • 您也不能为该方法创建新的泛型类型参数,并限制它以与结构的类型参数匹配,除非要删除结构类型的生存期

因此,rust的类型系统当前不支持我要完成的操作。请让我知道我的假设之一是否错误。

0 个答案:

没有答案