[英]Is there a elegant implement of the Iterator for the Rc<RefCell<T>> in Rust?
When I tried to implement the SkipList by rust, I was trapped by the implement of Iterator
of Rc<RefCell<T>>
.当我试图通过 rust 实现 SkipList 时,我被
Rc<RefCell<T>>
的Iterator
的实现所困。 Code is listed:代码如下:
pub struct SkipList<K, V>
{
head: Rc<RefCell<SkipNode<K, V>>>,
rng: rand::rngs::ThreadRng,
len: usize,
}
impl<K: Ord, V> SkipList<K, V> {
// ...
pub fn iter(&self) -> Iter<K, V> {
let next = &RefCell::borrow(&self.head).next_by_height[0];
Iter {
ptr: next.as_ref().map(|ref cell|Rc::clone(cell)),
_marker: Default::default(),
}
}
}
struct SkipNode<K, V> {
entry: Entry<K, V>,
next_by_height: [Option<Rc<RefCell<SkipNode>>>; MAX_HEIGHT],
}
pub struct Entry<K, V> {
key: K,
value: V,
}
struct SkipNode<K, V> {
entry: Option<Entry<K, V>>,
next_by_height: SkipTrack<K, V>,
}
pub struct Iter<'a, K: Ord, V>
{
ptr: Option<Rc<RefCell<SkipNode<K, V>>>>, //1
_marker: marker::PhantomData<&'a K>,
}
impl<'a, K, V: 'a> Iterator for Iter<'a, K, V>
where K: Ord
{
type Item = Ref<'a, Entry<K, V>>; //2
fn next(&mut self) -> Option<Self::Item> {
self.ptr.take().map(|node| { //3
let current = RefCell::borrow(&node);
self.ptr = current.next_by_height[0].as_ref().map(|ref node| Rc::clone(node));
Ref::map(current, |ref wrapped|{
&wrapped.entry.unwrap()
})
})
}
}
and the error is:错误是:
Compiling RclessRefCelllessTgreatergreater-Rust v0.1.0 (/home/runner/RclessRefCelllessTgreatergreater-Rust)
error[E0515]: cannot return reference to temporary value
--> main.rs:138:15
|
138 | &wrapped.entry.unwrap()
| ^----------------------
| ||
| |temporary value created here
| returns a reference to data owned by the current function
error[E0507]: cannot move out of `wrapped.entry` which is behind a shared reference
--> main.rs:138:16
|
138 | &wrapped.entry.unwrap()
| ^^^^^^^^^^^^^
| |
| move occurs because `wrapped.entry` has type `std::option::Option<Entry<K, V>>`, which does not implement the `Copy` trait
| help: consider borrowing the `Option`'s content: `wrapped.entry.as_ref()`
error[E0515]: cannot return value referencing function parameter `node`
--> main.rs:137:13
|
135 | let current = RefCell::borrow(&node);
| ----- `node` is borrowed here
136 | self.ptr = current.next_by_height[0].as_ref().map(|ref node| Rc::clone(node));
137 | / Ref::map(current, |ref wrapped|{
138 | | &wrapped.entry.unwrap()
139 | | })
| |______________^ returns a value referencing data owned by the current function
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0507, E0515.
For more information about an error, try `rustc --explain E0507`.
error: could not compile `RclessRefCelllessTgreatergreater-Rust`.
the full code is avaliable at Repl.it .完整代码可在Repl.it 获得。
I attempted to take the Ref<T>
as the Item returned by Iterator
, but the code is complained by the Rust complier that next
could not return a temporary variable.我试图将
Ref<T>
作为Iterator
返回的 Item ,但是 Rust 编译器抱怨代码next
无法返回临时变量。 Is there any Silver Bullet to achieve the Iterator
for the wrapped cell?是否有任何灵丹妙药来实现包装单元的
Iterator
?
Is there a elegant implement of the Iterator for the Rc<RefCell> in Rust?
Rust 中的 Rc<RefCell> 的迭代器是否有优雅的实现?
Not really.并不真地。 There's two big things in your way.
你的路上有两件大事。
One limitation when building an Iterator
is that the output type cannot reference the iterator itself.构建
Iterator
时的一个限制是 output 类型不能引用迭代器本身。 It can either return an owned value (no lifetimes involved) or return references bound to the lifetime of some other object.它可以返回一个拥有的值(不涉及生命周期)或返回绑定到其他一些 object 的生命周期的引用。
I see you've tried to communicate that you want to return Ref
s bound to the lifetime of the orignal SkipList
by using PhantomData<&'a K>
and also using 'a
in your Iterator::Item
.我看到您已尝试通过使用
PhantomData<&'a K>
并在Iterator::Item
中使用'a
来传达您希望返回绑定到原始SkipList
生命周期的Ref
的信息。 However, since your iterator can only source values from ptr
, an owned value with no lifetime-linkage to 'a
, the compiler will complain about mismatched lifetimes at one point or another.但是,由于您的迭代器只能从
ptr
获取值,这是一个与'a
没有生命周期链接的拥有值,因此编译器会在某一时刻抱怨生命周期不匹配。
In order to do this, your iterator would have to use something bound to 'a
, probably some form of Option<Ref<'a, _>>
.为了做到这一点,你的迭代器必须使用绑定到
'a
东西,可能是某种形式的Option<Ref<'a, _>>
。
However, another limitation is when you have nested RefCell
s, with each level that you iterate, you need to keep around an additional Ref
.但是,另一个限制是当您嵌套
RefCell
时,对于您迭代的每个级别,您都需要保留一个额外的Ref
。 The reason being that borrows from a Ref
don't keep the lifetime of the RefCell
, but from the Ref
itself.原因是从
Ref
借用的不是保持RefCell
的生命周期,而是从Ref
本身。
let refc = RefCell::new(RefCell::new(RefCell::new(42)));
let ref1 = refc.borrow(); // these all need
let ref2 = ref1.borrow(); // to be preserved
let ref3 = ref2.borrow(); // to access `v`
let v = &*ref3;
So if you try to keep only one Ref
chained from another, its going to encounter a "returns a value referencing data owned by the current function" error in one form or another.因此,如果您尝试仅将一个
Ref
与另一个链接起来,它将以一种或另一种形式遇到“返回引用当前函数拥有的数据的值”错误。 If you instead try to keep all those Ref
s within the iterator, well then it creates a self-referential struct.如果您尝试将所有这些
Ref
保留在迭代器中,那么它会创建一个自引用结构。 Not nice.不太好。
You can only get out of this issue by cloning the Rc
s at each level (which you've already done) to to get an owned value and escape the lifetime of the previous Ref
.您只能通过在每个级别(您已经完成)克隆
Rc
来摆脱这个问题,以获得拥有的价值并逃避前一个Ref
的生命周期。
So you cannot return a reference type for your iterator.所以你不能为你的迭代器返回一个引用类型。 Your only option is to return an owned value, which in this case wouldn't be ideal since it'd either have to be a cloned
Entry
, or an Rc<RefCell<SkipNode<K, V>>>
, or a wrapper around an Rc
that exposes the Entry
properly.您唯一的选择是返回一个拥有的值,在这种情况下这并不理想,因为它必须是一个克隆的
Entry
,或者一个Rc<RefCell<SkipNode<K, V>>>
,或者一个包装器正确公开Entry
的Rc
。
Here's a working version.这是一个工作版本。 The
EntryRef
wrapper I added could probably be better but it works and demonstrates the point.我添加的
EntryRef
包装器可能会更好,但它可以工作并证明了这一点。
pub struct EntryRef<K, V> {
ptr: Rc<RefCell<SkipNode<K, V>>>,
}
impl<K, V> EntryRef<K, V> {
pub fn get_entry(&self) -> Ref<'_, Entry<K, V>> {
Ref::map(self.ptr.borrow(), |node| node.entry.as_ref().unwrap())
}
}
pub struct Iter<K: Ord, V> {
ptr: Option<Rc<RefCell<SkipNode<K, V>>>>,
}
impl<K, V> Iterator for Iter<K, V>
where
K: Ord,
{
type Item = EntryRef<K, V>;
fn next(&mut self) -> Option<Self::Item> {
self.ptr.take().map(|node| {
self.ptr = node.borrow().next_by_height[0]
.as_ref()
.map(|ref node| Rc::clone(node));
EntryRef { ptr: node }
})
}
}
See also:也可以看看:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.