use std::cell::RefCell;
use std::ops::Add;
struct MyData<'a> {
data: RefCell<&'a mut dyn MyTrait>,
}
trait MyTrait {}
impl<'a> MyTrait for &'a mut i32 {}
impl<'a, 'b> MyTrait for (&'a mut dyn MyTrait, &'b mut dyn MyTrait) {}
impl<'a, 'b> MyTrait for &'b MyData<'a> {}
impl<'a> Add for MyData<'a> {
type Output = Self;
fn add(self, other: Self) -> Self::Output {
MyData {
data: RefCell::new(Box::leak(Box::new(
(self.data.into_inner(), other.data.into_inner())
))),
}
}
}
impl<'a, 'b> Add for &'b MyData<'a> {
type Output = MyData<'b>;
fn add(self, other: Self) -> Self::Output {
MyData {
data: RefCell::new(Box::leak(Box::new(
(Box::leak(Box::new(self)) as &mut dyn MyTrait,
Box::leak(Box::new(other)) as &mut dyn MyTrait)
))),
}
}
}
impl<'a, 'b> Add<&'b MyData<'a>> for MyData<'a> {
type Output = MyData<'b>;
fn add(self, other: &'b MyData<'a>) -> Self::Output {
MyData {
data: RefCell::new(Box::leak(Box::new(
(self.data.into_inner(),
Box::leak(Box::new(other)) as &mut dyn MyTrait)
))),
}
}
}
fn main() {
let mut n = 1;
let mut ref_n = &mut n;
let x = MyData { data: RefCell::new(&mut ref_n) };
let y = &x + &x;
//let _ = y + &x;
drop(x);
}
这段代码重载了三个加法运算:
fn add(_: MyData<'a>, _: MyData<'a>) -> MyData<'a>
fn add(_: &'b MyData<'a>, _: &'b MyData<'a>) -> MyData<'b>
fn add(_: MyData<'a>, _: &'b MyData<'a>) -> MyData<'b>
main
函数里面的let _ = y + &x;
注释掉可以通过检查,但加上这句会报错,想知道问题出在哪以及如何修改。
playground链接附在后面。
Ext Link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=497b781639a77c058ec2075fa4568b0f
1
共 9 条评论, 1 页
评论区
写评论加了一个
PhantomData
来表示每个Digits
对象的生命周期,并且不打算让'a
发生改变了,所有RefCell
的引用的生命周期都与内存池相同。这样Add
trait可以像下面那样重载,因为'c
是covariance的。&'a RefCell<DigitsDatum<'a>
也是一个永久借用,所以你可能要引入一个生命周期参数&'b RefCell<DigitsDatum<'a>
。h 的生命周期标注无法应用到 Add trait 上,搜索了一下,是因为
'c
只出现在了关联类型上,从而它需要变成 GAT,即type Output<'c> where 'a: 'c, 'b: 'c;
。解决方法是impl MyData
里面playground
按照我对invariance的理解,这里对
f
,g
,h
的标注应该更符合我本意,但h
的标注用在Add
trait上会报"unconstrained lifetime parameter"错误,请问这种情况该怎么表达约束?--
👇
苦瓜小仔: 文章在这:当
&'a Type<'a>
变成了永远借用:与生命周期标注交互我简化了代码(但函数签名没变),如果你只想知道原帖的代码思路,见注释: playground (简化了一些无关核心问题的代码)
改成
MyData<'b>
能通过的原因,见注释:playground解释一下做出这种设计的动机。我想实现一个对实数作精确运算的类,采用了如下这种带记忆的迭代器来表达一个惰性求值的无限不循环小数:
这里的
Bump
是arena内存池,BVec
是分配在其中的Vec
。在本提问中这不是一个很重要的点,所以我用Box::leak()
来代替了其上的内存分配。由于一个固定的实数对外界来说是不变的,但对其每一个数位的求值需要改变迭代器,所以引入了内部可变性。如果这一块有更好的设计也欢迎留言讨论。感谢解答👍
--
👇
苦瓜小仔: 文章在这:当
&'a Type<'a>
变成了永远借用:与生命周期标注交互我简化了代码(但函数签名没变),如果你只想知道原帖的代码思路,见注释: playground (简化了一些无关核心问题的代码)
改成
MyData<'b>
能通过的原因,见注释:playground文章在这:当
&'a Type<'a>
变成了永远借用:与生命周期标注交互我简化了代码(但函数签名没变),如果你只想知道原帖的代码思路,见注释: playground (简化了一些无关核心问题的代码)
改成
MyData<'b>
能通过的原因,见注释:playground我能够解释,但可能内容会很长,打算用一篇文章来描述 :)
--
👇
yuyidegit:
改成
十分感谢!但还是想知道为什么前一种写法不行,有没有什么调试工具可以看到编译器内部处理这些生命周期约束的过程?
改成