繁体   English   中英

带引用的通用参数用作函数指针参数

[英]Generic parameter with reference used as function pointer argument

我无法弄清楚哪个生命周期参数对此有效,因此我当前的解决方法包括转换或原始指针。 我有一个结构包含一个函数指针,以泛型为参数:

struct CB<Data> {
    cb: fn(Data) -> usize
}

我想存储一个实例,由包含引用的某种类型参数化,存储在一些其他结构中,该结构使用一种方法实现特征,并使用该特征方法调用 CB 中的函数指针。

struct Holder<'a> {
    c: CB<Option<&'a usize>>
}
trait Exec {
    fn exec(&self, v: &usize) -> usize;
}
impl<'a> Holder<'a> {
    fn exec_aux(&self, v: &'a usize) -> usize {
        (self.c.cb)(Some(v))
    }
}
impl<'a> Exec for Holder<'a> {
    fn exec(&self, v: &usize) -> usize
    {
        self.exec_aux(v)
    }
}

对于 Holder 的“Exec”实现,这给了我一个终生错误:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements

只要我不定义Exec impl,简单地调用exec_aux可以正常工作:

fn main() {
    let h = Holder { c: CB{cb:cbf}};
    let v = 12;
    println!("{}", h.exec_aux(&v));
}

此外,使 CB 不通用也使这项工作:

struct CB {
    cb: fn(Option<&usize>) -> usize
}

我的实际代码中的参数不是使用usize而是我不想复制的大参数。

你的Exec trait 中的生命周期是这样的:

trait Exec {
    fn exec<'s, 'a>(&'s self, v: &'a usize) -> usize;
}

换句话说,实现Exec类型需要接受任何生命周期's'a 但是,您的Holder::exec_aux方法需要一个特定的生命周期'a ,它与Holder类型的生命周期参数相关联。

要使其工作,您需要将'a作为生命周期参数添加到Exec特征,以​​便您可以专门为该生命周期实现特征:

trait Exec<'a> {
//        ^^^^         vv
    fn exec(&self, v: &'a usize) -> usize;
}

impl<'a> Exec<'a> for Holder<'a> {
//           ^^^^      vv
    fn exec(&self, v: &'a usize) -> usize
    {
        self.exec_aux(v)
    }
}

这里的问题是Exec trait 太通用了,不能被Holder以这种方式使用。 首先,考虑定义:

trait Exec {
    fn exec(&self, v: &usize) -> usize;
}

此定义将导致编译器自动为exec &self&v分配两个匿名生命周期。 它基本上与

fn exec<'a, 'b>(&'a self, v: &'b usize) -> usize;

请注意,对于谁需要比谁存活时间长没有限制,引用只需要在方法调用期间保持存活即可。

现在考虑定义

impl<'a> Holder<'a> {
    fn exec_aux(&self, v: &'a usize) -> usize {
        // ... doesn't matter
    }
}

既然我们知道&self是一个&Holder<'a> (这就是impl所指的),我们这里至少需要有一个&'a Holder<'a> ,因为&'_ self不能有生命周期比Holder<'a> 'a短。 所以这就是说这两个参数具有相同的生命周期: &'a self, &'a usize

当您尝试将两者结合起来时,一切都会出错。 该特征迫使您进入以下签名,该签名(再次)具有两个不同的隐式生命周期。 但是,您随后尝试对其调用方法的实际Holder迫使您对&self&v具有相同的生命周期。

fn exec(&self, v: &usize) -> usize {
    // Holder<'a> needs `v` to be `'a` when calling exec_aux
    // But the trait doesn't say so.
    self.exec_aux(v)
}

一种解决方案是将特征重新定义为

trait Exec<'a> {
    fn exec(&'a self, v: &'a usize) -> usize;
}

然后将其实现为

impl<'a> Exec<'a> for Holder<'a> {
    fn exec(&'a self, v: &'a usize) -> usize {
        self.exec_aux(v)
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM