我是否错误地实现了 IntoIterator 以引用 LazyList 实现,或者这是一个 Rust bug?

2023-11-29

在实现 LazyList 的一个版本(一个不可变的延迟计算的记忆单链表,就像 Haskell 列表)时,我遇到了实现的问题IntoIterator因为当我认为应该删除引用时,代码不会删除引用。以下代码已被简化,只是为了显示问题;因此,它不是通用的,并且不包括与实现无关的所有方法IntoIterator:

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);
    }
}

上面的代码失败并显示:

rustc 1.13.0 (2c6933acc 2016-11-07)
error: `test` does not live long enough
   --> <anon>:103:40
    |
103 |     let itr = IntoIterator::into_iter(&test); // not working
    |                                        ^^^^ does not live long enough
...
107 | }
    | - borrowed value dropped before borrower
    |
    = note: values in a scope are dropped in the opposite order they are created

正如评论中指出的main(),代码可用除非通过 IntoIterator 特征作为引用调用。这可能是实现引用特征时的一个错误,其中包含指针的返回迭代器的所有权未转移到与调用相同的范围IntoIterator::into_iter而是为了'static因此,它不会在预期时被丢弃。

如果可能的话,我该如何实施?我试过添加一个std::marker::PhantomData<>标记字段到Iterstruct 但似乎也被分配了一个'static寿命。


当你实施IntoIterator,您统一了对列表的引用和列表包含的项目之间的生命周期:

impl<'a> IntoIterator for &'a LazyList<'a>

这就要求'a必须是寿命中较短的一个。这在这种情况下没有用。相反,您需要有两个不同的生命周期:

impl<'l, 'i> IntoIterator for &'l LazyList<'i> {
    type Item = &'i i32;
    type IntoIter = Iter<'i>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我是否错误地实现了 IntoIterator 以引用 LazyList 实现,或者这是一个 Rust bug? 的相关文章

随机推荐

  • WinSCP 命令行:在缓存错误中找不到主机密钥

    我第一次尝试从 WinSCP 命令行连接到 Unix 服务器 它关闭并出现以下错误 在缓存中找不到服务器的主机密钥 您无法保证 服务器是您认为的计算机 服务器的 rsa2 密钥指纹是 ssh rsa 1024 42 9e c7 f4 7f
  • 在 C++14 中使用 auto 作为返回值和参数类型

    在 Bjarne Stroustrup 的书 C 编程语言 的第四版中 我们读到 使用 auto 我们可以避免冗余和编写长类型名称 这在泛型编程中尤其重要 因为程序员很难知道对象的确切类型 并且类型名称可能很长 第 4 5 1 节 所以 了
  • iReport 中每个组的新页面

    我正在使用 iReport 5 6 0 我想为每个组创建新页面 例如我有桌子people i know Id Name State 1 Tom friends 2 Jim friends 3 Mike enemy 4 Alex friend
  • 使用 pyuic 将 .ui 转换为 .py?

    我正在使用 OSX 10 8 python 2 7 5 我刚刚使用 QtDesigner 构建了一个 GUI 并试图弄清楚如何在 Python 中使用它 我发现我必须使用 pyuic 以及如何在此处执行此操作 pyqt在mac osx雪豹中
  • asp.net通过kerberos将Windows身份验证集成到sql服务器

    请问有人可以提供一种简单 直接的方法来启用 ASP NET gt Kerberos gt Sql Server 吗 我们有客户端机器 gt 网络服务器 gt 数据库服务器 客户端坚持要求站点必须拉取 Windows 登录名而不是提示 因此需
  • Java 中的强制可克隆接口

    我在 Java 中遇到了一个小问题 我有一个名为 可修改 的界面 实现此接口的对象是可修改的 我还有一个 ModifyCommand 类 具有命令模式 它接收两个可修改对象 以进一步在列表中交换它们 这不是我的问题 我已经设计了该解决方案
  • 如何使用 FormData API 发出 POST 请求

    我想使用 http post 将用户名和 form data 对象传递到 php 文件 当我只传递 form data 时 它可以上传我的图片 但我还想传递一些其他信息 例如用户名 请帮助我如何在 http post 中传递其他数据 这是我
  • Mongoose 仅​​选择在架构中明确声明的字段

    当使用 Mongoose 并查询数据库时 默认情况下会选择所有字段 并且我必须明确告诉 Mongoose 我不想选择哪些字段 例如 如果我不想要该字段user我应该做 var schema new Schema insertedAt typ
  • 从 GridView 项目中获取值

    我正在开发一个项目 其中有一个 5x5 的 TextView 网格 我想检查整行或整列是否具有相同的元素 我正在使用 Adapter 类来仅用一个 textview 元素来扩充我的 gridview 这是我尝试过的代码 但我似乎无法使其工作
  • Android 2.2 联系人生日日期

    我正在尝试从 android 2 2 的联系方式获取生日日期 有人可以帮我查询一下吗 这是我的代码 Override public void onCreate Bundle savedInstanceState super onCreate
  • socket.io 和不同的文件夹 --- 找到解决方案

    我是 socket io 的新手 我已经遇到了一个问题 我认为是小问题 我已经使用 npm 正确安装了 node js 和 socket io 然后为了测试 我从 socket io 剪切并粘贴了一个代码示例 一切正常 现在 我想构建我的代
  • PHP:imagepng 正在创建异常大的文件

    我正在使用我编写的一个简单的缩略图脚本 它非常标准 imgbuffer imagecreatetruecolor thumbwidth thumbheight switch type case 1 image imagecreatefrom
  • PHP PDO 扩展无法在 IIS 上运行

    我有一个使用 autoload 加载类的脚本 愚蠢 我知道 这是我用来娱乐 测试的旧代码 它似乎正在尝试自动加载 PDO 这让我相信它没有找到应有的 PDO 类 我已经检查了 php ini 和 php pdo dll 是否已启用 以及 p
  • 在 Android 上旋转 YUV 字节数组

    我正在寻找旋转从 Preview Callblack 收到的 YUV 帧预览 到目前为止 我已经创建了这篇文章 其中包含一种旋转帧预览的算法 但弄乱了预览图像相机像素旋转 旋转图像的另一种方法是从 YUV 图像创建 jpg 创建位图 旋转位
  • 生成一系列值之间的随机双精度值

    我目前无法生成 32 768 和 32 768 之间的随机数 它一直给我相同的值 但小数字段有微小的变化 例如 27 xxx 这是我的代码 任何帮助将不胜感激 include
  • 如果前一个参数为空,则参数没有默认值?

    我有这个查询 除非我尝试在参数中传递空值 否则它似乎可以工作 using OleDbCommand com new OleDbCommand INSERT INTO GROUP Group Number Group Name Address
  • 文件输入“接受”属性 - 有用吗?

    在html下实现文件上传相当简单 但我只是注意到有一个 accept 属性可以添加到
  • 以编程方式禁用键盘和鼠标

    有没有办法禁用键盘和鼠标 Ideally I m looking for a solution whereby I could completely disable mouse and almost disable the keyboard
  • xsltproc 不按名称选择元素

    我正在尝试使用 XSLT 样式表转换 XHTML 但我什至无法获得基本样式表来匹配任何内容 我确信我错过了一些简单的事情 这是我的 XHTML 源文档 没什么大惊喜
  • 我是否错误地实现了 IntoIterator 以引用 LazyList 实现,或者这是一个 Rust bug?

    在实现 LazyList 的一个版本 一个不可变的延迟计算的记忆单链表 就像 Haskell 列表 时 我遇到了实现的问题IntoIterator因为当我认为应该删除引用时 代码不会删除引用 以下代码已被简化 只是为了显示问题 因此 它不是