通过引用实现特征关联类型的生命周期

问题描述 投票:0回答:1

我有一个具有关联类型的特征,但我想用引用类型来实现它,但是我无法获得正确的生命周期。

例如,没有参考文献,假设我有:

trait DoesStuff {
    type Output;
    
    fn do_thing(&mut self, x: f64) -> Self::Output;
}

struct SummingWidget {
    sum_so_far: f64
}

impl SummingWidget {
    pub fn new() -> Self {
        Self{
            sum_so_far: 0.0
        }
    }
}

impl DoesStuff for SummingWidget {
    type Output = f64;
    
    fn do_thing(&mut self, x: f64) -> Self::Output {
        self.sum_so_far += x;
        self.sum_so_far
    }
}

然后一切正常。但假设我不想返回该值,而是只想返回对该对象所持有的值的引用。仅返回引用的明显尝试会导致对关联类型的生命周期的请求。

    type Output = &f64;

向关联类型添加生命周期需要将其添加到 impl,然后它就不受约束,因此我尝试将其添加到结构中,然后需要一个 PhantomData,最终得到:

struct SummingWidgetRef<'a> {
    sum_so_far: f64,
    phantom: PhantomData<&'a ()>
}

impl<'a> SummingWidgetRef<'a> {
    pub fn new() -> Self {
        Self{
            sum_so_far: 0.0,
            phantom: PhantomData,
        }
    }
}

impl<'a> DoesStuff for SummingWidgetRef<'a> {
    type Output = &'a f64;
    
    fn do_thing(&mut self, x: f64) -> Self::Output {
        self.sum_so_far += x;
        &self.sum_so_far
    }
}

但即使这样也不好,因为编译器会抱怨:

method was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`

此时我陷入了困境。我如何告诉编译器返回类型应该与结构的生命周期匹配?

rust reference traits lifetime associated-types
1个回答
0
投票

最初的做法是让trait按值取

self
,然后实现以供参考。

trait DoesStuff {
    type Output;
    
    fn do_thing(self, x: f64) -> Self::Output;
}

pub struct SummingWidget {
    sum_so_far: f64
}

impl<'a> DoesStuff for &'a mut SummingWidget {
    type Output = &'a f64;
    
    fn do_thing(self, x: f64) -> Self::Output {
        self.sum_so_far += x;
        &self.sum_so_far
    }
}

这在大多数情况下都有效,这就是几个标准库实现的工作原理,例如

impl<'a, T> IntoIterator for &'a [T]

新选项是使用通用关联类型(GAT)(来自eggyal的评论)。

trait DoesStuff {
    type Output<'a> where Self: 'a;
    
    fn do_thing(&mut self, x: f64) -> Self::Output<'_>;
}

pub struct SummingWidget {
    sum_so_far: f64
}

impl DoesStuff for SummingWidget {
    type Output<'a> = &'a f64;
    
    fn do_thing(&mut self, x: f64) -> Self::Output<'_> {
        self.sum_so_far += x;
        &self.sum_so_far
    }
}

我相信原始方法比 GAT 方法稍微灵活一些,因为您可以选择

do_thing
采用任何类型,而 GAT 方法必须采用
&mut
。但如果您有比示例中的简单函数更复杂的东西,您可能需要使用 GAT 方法。

© www.soinside.com 2019 - 2024. All rights reserved.