Rust 我是不是为了引用懒人列表实现而错误地实现了IntoIterator,还是这是一个生锈的bug?
在实现LazyList的一个版本(一个不可变的、延迟计算的、记忆化的单链表,就像Haskell列表一样)时,我遇到了一个问题,即在迭代器中实现Rust 我是不是为了引用懒人列表实现而错误地实现了IntoIterator,还是这是一个生锈的bug?,rust,lifetime,borrow-checker,borrowing,lifetime-scoping,Rust,Lifetime,Borrow Checker,Borrowing,Lifetime Scoping,在实现LazyList的一个版本(一个不可变的、延迟计算的、记忆化的单链表,就像Haskell列表一样)时,我遇到了一个问题,即在迭代器中实现时,代码不会在我认为应该的时候删除引用。以下代码已简化,以便显示问题;因此,它不是泛型的,并且不包括与在迭代器中实现无关的所有方法: use std::cell::UnsafeCell; use std::mem::replace; use std::rc::Rc; // only necessary because Box<FnOnce() -&
时,代码不会在我认为应该的时候删除引用。以下代码已简化,以便显示问题;因此,它不是泛型的,并且不包括与在迭代器中实现无关的所有方法:
use std::cell::UnsafeCell;
use std::mem::replace;
use std::rc::Rc;
// only necessary because Box<FnOnce() -> R> doesn't yet work...
trait Invoke<R = ()> {
fn invoke(self: Box<Self>) -> R;
}
impl<'a, R, F: 'a + FnOnce() -> R> Invoke<R> for F {
#[inline(always)]
fn invoke(self: Box<F>) -> R {
(*self)()
}
}
// not thread safe
struct Lazy<'a, T: 'a>(UnsafeCell<LazyState<'a, T>>);
enum LazyState<'a, T: 'a> {
Unevaluated(Box<Invoke<T> + 'a>),
EvaluationInProgress,
Evaluated(T),
}
use self::LazyState::*;
impl<'a, T: 'a> Lazy<'a, T> {
#[inline]
fn new<F: 'a + FnOnce() -> T>(func: F) -> Lazy<'a, T> {
Lazy(UnsafeCell::new(Unevaluated(Box::new(func))))
}
#[inline]
pub fn evaluated(val: T) -> Lazy<'a, T> {
Lazy(UnsafeCell::new(Evaluated(val)))
}
#[inline]
fn value(&'a self) -> &'a T {
unsafe {
match *self.0.get() {
Evaluated(_) => (), // nothing required; already Evaluated
EvaluationInProgress => panic!("Lazy::force called recursively!!!"),
_ => {
let ue = replace(&mut *self.0.get(), EvaluationInProgress);
if let Unevaluated(thnk) = ue {
*self.0.get() = Evaluated(thnk.invoke());
} // no other possiblity!
}
} // following just gets evaluated, no other state possible
if let Evaluated(ref v) = *self.0.get() {
return v;
} else {
unreachable!();
}
}
}
}
enum LazyList<'a> {
Empty,
Cons(i32, RcLazyListNode<'a>),
}
type RcLazyListNode<'a> = Rc<Lazy<'a, LazyList<'a>>>;
impl<'a> LazyList<'a> {
fn iter(&self) -> Iter<'a> {
Iter(self)
}
}
struct Iter<'a>(*const LazyList<'a>);
impl<'a> Iterator for Iter<'a> {
type Item = &'a i32;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
if let LazyList::Cons(ref v, ref r) = *self.0 {
self.0 = r.value();
Some(v)
} else {
None
}
}
}
}
impl<'a> IntoIterator for &'a LazyList<'a> {
type Item = &'a i32;
type IntoIter = Iter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
fn main() {
let test2 = LazyList::Cons(2, Rc::new(Lazy::evaluated(LazyList::Empty)));
let test = LazyList::Cons(1, Rc::new(Lazy::new(move || test2)));
// let itr = Iter(&test); // works
// let itr = (&test).iter(); // works
let itr = IntoIterator::into_iter(&test); // not working
for v in itr {
println!("{}", v);
}
}
使用std::cell::UnsafeCell;
使用std::mem::replace;
使用std::rc::rc;
//只是因为框R>还不起作用才有必要。。。
特征调用{
fn调用(self:Box)->R;
}
impl R>为F调用{
#[在线(始终)]
fn调用(self:Box)->R{
(*自我)()
}
}
//线程不安全
结构懒惰(未完成),
评估进展,
评估(T),
}
使用self::LazyState::*;
impl Lazy T>(func:F)->Lazy{
Lazy(unsecell::new(Evaluated(val)))
}
#[内联]
fn值(&'a self)->&'T{
不安全{
匹配*self.0.get(){
已评估()=>(),//不需要任何内容;已评估
EvaluationInProgress=>panic!(“Lazy::force递归调用!!!”),
_ => {
让ue=replace(&mut*self.0.get(),EvaluationInProgress);
如果让未评估(thnk)=ue{
*self.0.get()=已计算(thnk.invoke());
}//没有其他可能!
}
}//仅计算以下值,不可能有其他状态
如果让求值(ref v)=*self.0.get(){
返回v;
}否则{
遥不可及!();
}
}
}
}
enum LazyList),
}
类型RcLazyListNode LazyList{
Iter(自我)
}
}
结构(Iter);
恳求{
类型项=&'aI32;
fn下一步(&mut self)->选项{
不安全{
如果让懒汉列表::Cons(ref v,ref r)=*self.0{
self.0=r.value();
部分(五)
}否则{
没有一个
}
}
}
}
impl当您在迭代器中实现时,您统一了对列表的引用和列表包含的项之间的生命周期:
impl<'a> IntoIterator for &'a LazyList<'a>
对于那些通过搜索Rust、Lazy和LazyList来发现这个问题的人,我在这里发布了Lazy和LazyList的最终通用工作代码,其中包括使用当前稳定的Rust版本1.13的非安全版本和线程安全版本
代码中包含一些测试代码没有实际使用的方法,尤其是unwrap()
方法在这里是无用的,因为我们不能使用嵌入到另一个类型中的类型(除非我们替换内部可变值);需要为singleton()
方法、unwrap()
方法和tail()
方法设计更多的测试
因为我们通常无法展开,所以嵌入的类型必须是克隆;这会在涉及的复制操作中损失一些性能,因此,当类型较大(按复制方式)时,可能需要将它们包装在Rc中,以便更快地进行引用计数克隆
代码如下:
// only necessary because Box<FnOnce() -> R> doesn't work...
mod thunk {
pub trait Invoke<R = ()> {
fn invoke(self: Box<Self>) -> R;
}
impl<R, F: FnOnce() -> R> Invoke<R> for F {
#[inline(always)]
fn invoke(self: Box<F>) -> R { (*self)() }
}
}
// Lazy is lazily evaluated contained value using the above Invoke trait
// instead of the desire Box<FnOnce() -> T> or a stable FnBox (currently not)...
mod lazy {
use thunk::Invoke;
use std::cell::UnsafeCell;
use std::mem::replace;
use std::ops::Deref;
// Lazy is lazily evaluated contained value using the above Invoke trait
// instead of the desire Box<FnOnce() -> T> or a stable FnBox (currently not)...
pub struct Lazy<'a, T: 'a>(UnsafeCell<LazyState<'a, T>>);
enum LazyState<'a, T: 'a> {
Unevaluated(Box<Invoke<T> + 'a>),
EvaluationInProgress,
Evaluated(T),
}
use self::LazyState::*;
// impl<'a, T:'a> !Sync for Lazy<'a, T> {}
impl<'a, T: 'a> Lazy<'a, T> {
#[inline]
pub fn new<F: 'a + FnOnce() -> T>(func: F) -> Lazy<'a, T> {
Lazy(UnsafeCell::new(Unevaluated(Box::new(func))))
}
#[inline]
pub fn evaluated(val: T) -> Lazy<'a, T> {
Lazy(UnsafeCell::new(Evaluated(val)))
}
#[inline(always)]
fn force<'b>(&'b self) {
unsafe {
match *self.0.get() {
Evaluated(_) => return, // nothing required; already Evaluated
EvaluationInProgress => panic!("Lazy::force called recursively!!!"),
_ => {
let ue = replace(&mut *self.0.get(), EvaluationInProgress);
if let Unevaluated(thnk) = ue {
*self.0.get() = Evaluated(thnk.invoke());
} // no other possiblity!
}
}
}
}
#[inline]
pub fn unwrap<'b>(self) -> T where T: 'b { // consumes the object to produce the value
self.force(); // evaluatate if not evealutated
match unsafe { self.0.into_inner() } {
Evaluated(v) => v,
_ => unreachable!() // previous code guarantees never not Evaluated
}
}
}
impl<'a, T: 'a> Deref for Lazy<'a, T> {
type Target = T;
#[inline]
fn deref<'b>(&'b self) -> &'b T {
self.force(); // evaluatate if not evalutated
match unsafe { &*self.0.get() } {
&Evaluated(ref v) => return v,
_ => unreachable!(),
}
}
}
}
mod lazy_sync {
use thunk::Invoke;
use std::cell::UnsafeCell;
use std::mem::replace;
use std::sync::Mutex;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::Relaxed;
use std::ops::Deref;
pub struct Lazy<'a, T: 'a + Send + Sync>(
UnsafeCell<LazyState<'a, T>>, AtomicBool, Mutex<()>);
enum LazyState<'a, T: 'a + Send + Sync> {
Unevaluated(Box<Invoke<T> + 'a>),
EvaluationInProgress,
Evaluated(T),
}
use self::LazyState::*;
unsafe impl<'a, T: 'a + Send + Sync> Send for Lazy<'a, T> {}
unsafe impl<'a, T: 'a + Send + Sync> Sync for Lazy<'a, T> {}
impl<'a, T: 'a + Send + Sync> Lazy<'a, T> {
#[inline]
pub fn new<F: 'a + FnOnce() -> T>(func: F) -> Lazy<'a, T> {
Lazy(UnsafeCell::new(Unevaluated(Box::new(func))),
AtomicBool::new(false), Mutex::new(()))
}
#[inline]
pub fn evaluated(val: T) -> Lazy<'a, T> {
Lazy(UnsafeCell::new(Evaluated(val)),
AtomicBool::new(true), Mutex::new(()))
}
#[inline(always)]
fn force<'b>(&'b self) {
unsafe {
if !self.1.load(Relaxed) {
let _ = self.2.lock();
// if we don't get the false below, means
// another thread already handled the thunk,
// including setting to true, still processing when checked
if !self.1.load(Relaxed) {
match *self.0.get() {
Evaluated(_) => return, // nothing required; already Evaluated
EvaluationInProgress => unreachable!(), // because lock race recursive evals...
_ => {
if let Unevaluated(thnk) = replace(&mut *self.0.get(), EvaluationInProgress) {
*self.0.get() = Evaluated(thnk.invoke());
} // no other possiblity!
}
}
self.1.store(true, Relaxed);
}
}
}
}
#[inline]
pub fn unwrap<'b>(self) -> T where T: 'b { // consumes the object to produce the value
self.force(); // evaluatate if not evealutated
match unsafe { self.0.into_inner() } {
Evaluated(v) => v,
_ => unreachable!() // previous code guarantees never not Evaluated
}
}
}
impl<'a, T: 'a + Send + Sync> Deref for Lazy<'a, T> {
type Target = T;
#[inline]
fn deref<'b>(&'b self) -> &'b T {
self.force(); // evaluatate if not evalutated
match unsafe { &*self.0.get() } {
&Evaluated(ref v) => return v,
_ => unreachable!(),
}
}
}
}
// LazyList is an immutable lazily-evaluated persistent (memoized) singly-linked list
// similar to lists in Haskell, although here only tails are lazy...
// depends on the contained type being Clone so that the LazyList can be
// extracted from the reference-counted Rc heap objects in which embedded.
mod lazylist {
use lazy::Lazy;
use std::rc::Rc;
use std::iter::FromIterator;
use std::mem::{replace, swap};
#[derive(Clone)]
pub enum LazyList<'a, T: 'a + Clone> {
Empty,
Cons(T, RcLazyListNode<'a, T>),
}
pub use self::LazyList::Empty;
use self::LazyList::Cons;
type RcLazyListNode<'a, T: 'a> = Rc<Lazy<'a, LazyList<'a, T>>>;
// impl<'a, T:'a> !Sync for LazyList<'a, T> {}
impl<'a, T: 'a + Clone> LazyList<'a, T> {
#[inline]
pub fn singleton(v: T) -> LazyList<'a, T> {
Cons(v, Rc::new(Lazy::evaluated(Empty)))
}
#[inline]
pub fn cons<F>(v: T, cntf: F) -> LazyList<'a, T>
where F: 'a + FnOnce() -> LazyList<'a, T>
{
Cons(v, Rc::new(Lazy::new(cntf)))
}
#[inline]
pub fn head<'b>(&'b self) -> &'b T {
if let Cons(ref hd, _) = *self {
return hd;
}
panic!("LazyList::head called on an Empty LazyList!!!")
}
#[inline]
pub fn tail<'b>(&'b self) -> &'b Lazy<'a, LazyList<'a, T>> {
if let Cons(_, ref rlln) = *self {
return &*rlln;
}
panic!("LazyList::tail called on an Empty LazyList!!!")
}
#[inline]
pub fn unwrap(self) -> (T, RcLazyListNode<'a, T>) {
// consumes the object
if let Cons(hd, rlln) = self {
return (hd, rlln);
}
panic!("LazyList::unwrap called on an Empty LazyList!!!")
}
#[inline]
fn iter(&self) -> Iter<'a, T> {
Iter(self)
}
}
impl<'a, T: 'a + Clone> Iterator for LazyList<'a, T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
match replace(self, Empty) {
Cons(hd, rlln) => {
let mut newll = (*rlln).clone();
swap(self, &mut newll); // self now contains tail, newll contains the Empty
Some(hd)
}
_ => None,
}
}
}
pub struct Iter<'a, T: 'a + Clone>(*const LazyList<'a, T>);
impl<'a, T: 'a + Clone> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
if let LazyList::Cons(ref v, ref r) = *self.0 {
self.0 = &***r;
Some(v)
} else {
None
}
}
}
}
impl<'i, 'l, T: 'i + Clone> IntoIterator for &'l LazyList<'i, T> {
type Item = &'i T;
type IntoIter = Iter<'i, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T: 'a + Clone> FromIterator<T> for LazyList<'a, T> {
fn from_iter<I: IntoIterator<Item = T> + 'a>(itrbl: I) -> LazyList<'a, T> {
let itr = itrbl.into_iter();
#[inline(always)]
fn next_iter<'b, R, Itr>(mut iter: Itr) -> LazyList<'b, R>
where R: 'b + Clone,
Itr: 'b + Iterator<Item = R>
{
match iter.next() {
Some(val) => LazyList::cons(val, move || next_iter(iter)),
None => Empty,
}
}
next_iter(itr)
}
}
}
mod lazylist_sync {
use lazy_sync::Lazy;
use std::sync::Arc as Rc;
use std::iter::FromIterator;
use std::mem::{replace, swap};
#[derive(Clone)]
pub enum LazyList<'a, T: 'a + Send + Sync + Clone> {
Empty,
Cons(T, RcLazyListNode<'a, T>),
}
pub use self::LazyList::Empty;
use self::LazyList::Cons;
type RcLazyListNode<'a, T: 'a> = Rc<Lazy<'a, LazyList<'a, T>>>;
unsafe impl<'a, T: 'a + Send + Sync + Clone> Send for LazyList<'a, T> {}
unsafe impl<'a, T: 'a + Send + Sync + Clone> Sync for LazyList<'a, T> {}
impl<'a, T: 'a + Send + Sync + Clone> LazyList<'a, T> {
#[inline]
pub fn singleton(v: T) -> LazyList<'a, T> {
Cons(v, Rc::new(Lazy::evaluated(Empty)))
}
#[inline]
pub fn cons<F>(v: T, cntf: F) -> LazyList<'a, T>
where F: 'a + FnOnce() -> LazyList<'a, T>
{
Cons(v, Rc::new(Lazy::new(cntf)))
}
#[inline]
pub fn head<'b>(&'b self) -> &'b T {
if let Cons(ref hd, _) = *self {
return hd;
}
panic!("LazyList::head called on an Empty LazyList!!!")
}
#[inline]
pub fn tail<'b>(&'b self) -> &'b Lazy<'a, LazyList<'a, T>> {
if let Cons(_, ref rlln) = *self {
return &*rlln;
}
panic!("LazyList::tail called on an Empty LazyList!!!")
}
#[inline]
pub fn unwrap(self) -> (T, RcLazyListNode<'a, T>) {
// consumes the object
if let Cons(hd, rlln) = self {
return (hd, rlln);
}
panic!("LazyList::unwrap called on an Empty LazyList!!!")
}
#[inline]
fn iter(&self) -> Iter<'a, T> {
Iter(self)
}
}
impl<'a, T: 'a + Send + Sync + Clone> Iterator for LazyList<'a, T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
match replace(self, Empty) {
Cons(hd, rlln) => {
let mut newll = (*rlln).clone();
swap(self, &mut newll); // self now contains tail, newll contains the Empty
Some(hd)
}
_ => None,
}
}
}
pub struct Iter<'a, T: 'a + Send + Sync + Clone>(*const LazyList<'a, T>);
impl<'a, T: 'a + Send + Sync + Clone> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
if let LazyList::Cons(ref v, ref r) = *self.0 {
self.0 = &***r;
Some(v)
} else {
None
}
}
}
}
impl<'i, 'l, T: 'i + Send + Sync + Clone> IntoIterator for &'l LazyList<'i, T> {
type Item = &'i T;
type IntoIter = Iter<'i, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T: 'a + Send + Sync + Clone> FromIterator<T> for LazyList<'a, T> {
fn from_iter<I: IntoIterator<Item = T> + 'a>(itrbl: I) -> LazyList<'a, T> {
let itr = itrbl.into_iter();
#[inline(always)]
fn next_iter<'b, R: 'b + Send + Sync, Itr>(mut iter: Itr) -> LazyList<'b, R>
where R: 'b + Clone,
Itr: 'b + Iterator<Item = R>
{
match iter.next() {
Some(val) => LazyList::cons(val, move || next_iter(iter)),
None => Empty,
}
}
next_iter(itr)
}
}
}
use self::lazylist::LazyList;
//use self::lazylist_sync::LazyList; // for slower thread-safe version
fn main() {
fn fib<'a>() -> LazyList<'a, u64> {
fn fibi<'b>(f: u64, s: u64) -> LazyList<'b, u64> {
LazyList::cons(f, move || { let n = &f + &s; fibi(s, n) })
}
fibi(0, 1)
}
let test1 = fib();
for v in test1.take(20) {
print!("{} ", v);
}
println!("");
let test2 = (0..).collect::<LazyList<_>>();
for i in (&test2).into_iter().take(15) {
print!("{} ", i)
} // and from_iter() works
}
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
注意,尽管这表明在Rust中使用LazyList的函数式编程风格是可能的,但这并不意味着它应该是所有用例的首选风格,特别是在需要高性能的情况下。例如,如果上面的fib()
函数被编写为直接输出迭代器,而不是LazyList
,那么每次迭代只需要很少的CPU时钟周期(除非使用了无限精度BigUint
,这会更慢)而不是LazyList每次迭代所需的数百个周期(以及“同步”版本所需的更多周期)
一般来说,由于引用计数的高开销、许多小的分配/取消分配以及函数式编程所需的克隆/复制,如果需要记忆,则可能使用Vec
的更强制的实现比这更高效。,一旦你看到它,它看起来是如此简单和明显,但我自己可能会花很长时间才偶然发现它。非常感谢。
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14