debugging - Rust:如何在闭包参数中指定生命周期?

标签 debugging iterator closures rust lifetime

我正在编写一个解析器生成器作为一个学习 Rust 的项目,但我遇到了一些我无法通过生命周期和闭包来解决的问题。这是我的简化案例(抱歉,它确实很复杂,但我需要在真实版本中使用自定义迭代器,它似乎对编译器的行为有所影响):

围栏链接:http://is.gd/rRm2aa

struct MyIter<'stat, T:Iterator<&'stat str>>{
    source: T
}

impl<'stat, T:Iterator<&'stat str>> Iterator<&'stat str> for MyIter<'stat, T>{
    fn next(&mut self) -> Option<&'stat str>{
        self.source.next()
    }
}

struct Scanner<'stat,T:Iterator<&'stat str>>{
    input: T
}

impl<'main> Scanner<'main, MyIter<'main,::std::str::Graphemes<'main>>>{
    fn scan_literal(&'main mut self) -> Option<String>{
        let mut token = String::from_str("");
        fn get_chunk<'scan_literal,'main>(result:&'scan_literal mut String, 
                                          input: &'main mut MyIter<'main,::std::str::Graphemes<'main>>) 
         -> Option<&'scan_literal mut String>{
            Some(input.take_while(|&chr| chr != "\"")
                 .fold(result, |&mut acc, chr|{
                     acc.push_str(chr);
                     &mut acc
                 }))
        }
        get_chunk(&mut token,&mut self.input);
        println!("token is {}", token);
        Some(token)
    }
}

fn main(){
    let mut scanner = Scanner{input:MyIter{source:"\"foo\"".graphemes(true)}};
    scanner.scan_literal();
}

我知道这里有两个问题。首先,我必须在 get_chunk 函数中隐藏 'main 生命周期(我尝试使用 impl 中的那个,但编译器提示 'main 中未定义>get_chunk).我认为它仍然会成功,因为稍后对 get_chunk 的调用会将 impl 中的 'main 中的 'main 匹配get_chunk,但我不确定这是对的。

第二个问题是闭包内的&mut acc 需要有'scan_literal 的生命周期才能像我希望的那样工作(累积字符直到这个例子中遇到了第一个 "。虽然我不能为 &mut acc 添加显式生命周期,编译器说它的生命周期仅限于闭包本身,并且因此我无法返回在下一次折叠迭代中使用的引用。我已经获得了以各种其他方式编译和运行的功能,但我不明白这里的问题是什么。

我的主要问题是:有没有办法显式指定闭包参数的生命周期?如果没有,是否有更好的方法来使用 fold 来累积字符串而不进行多次复制?

最佳答案

首先,关于生命周期。在其他函数内部定义的函数是静态的,它们与外部代码没有任何联系。因此,它们的生命周期参数是完全独立的。你不想使用 'main作为 get_chunk() 的生命周期参数因为它会遮挡外部 'main一生,除了困惑,别无他物。

接下来,关于闭包。这个表达式:

|&mut acc, chr| ...

很可能不是您真正认为的那样。闭包/函数参数允许在它们中使用无可辩驳的模式,并且 &在图案中有特殊意义。也就是说,它取消引用它所匹配的值,并将其标识符分配给这个取消引用的值:

let x: int = 10i;
let p: &int = &x;
match p {
    &y => println!("{}", y)  // prints 10
}

可以想到&& 相反的模式在表达式中:在表达式中表示“获取引用”,在模式中表示“删除引用”。

mut , 但是,不属于 &在模式中;它属于标识符,意味着具有此标识符的变量是可变的,即你应该写 not

|&mut acc, chr| ...

但是

|& mut acc, chr| ...

您可能对 this RFC 感兴趣这正是语言语法中的这个怪癖。

看起来你想做一件很奇怪的事情,我不确定我明白你的意思。您很可能混淆了不同的字符串类型。首先,你应该阅读 the official guide其中解释了所有权和借用以及何时使用它们(您可能还想阅读 unfinished ownership guide ;它将很快进入主文档树),然后您应该阅读 strings guide .

无论如何,您的问题可以通过更简单和通用的方式解决:

#[deriving(Clone)]
struct MyIter<'s, T: Iterator<&'s str>> {
    source: T
}

impl<'s, T: Iterator<&'s str>> Iterator<&'s str> for MyIter<'s, T>{
    fn next(&mut self) -> Option<&'s str>{ // '
        self.source.next()
    }
}

#[deriving(Clone)]
struct Scanner<'s, T: Iterator<&'s str>> {
    input: T
} 

impl<'m, T: Iterator<&'m str>> Scanner<'m, T> {  // '
    fn scan_literal(&mut self) -> Option<String>{
        fn get_chunk<'a, T: Iterator<&'a str>>(input: T) -> Option<String> {
            Some(
                input.take_while(|&chr| chr != "\"")
                     .fold(String::new(), |mut acc, chr| {
                         acc.push_str(chr);
                         acc
                     })
            )
        }
        let token = get_chunk(self.input.by_ref());
        println!("token is {}", token);
        token
    }
}

fn main(){
    let mut scanner = Scanner{
        input: MyIter {
            source: "\"foo\"".graphemes(true)
        }
    };
    scanner.scan_literal();
}

您不需要将外部引用传递到闭包中;你可以生成一个 String直接在fold()手术。我还对您的代码进行了泛化,使其更加地道。

注意现在 impl对于 Scanner也适用于返回 &str 的任意迭代器.很可能你想写这个而不是专攻 Scanner仅适用于 MyIterGraphemes在里面。 by_ref()操作转&mut I其中 I是一个 Iterator<T>进入J , 其中J是一个 Iterator<T> .即使您只有对原始迭代器的可变引用,它也允许进一步链接迭代器。

顺便说一句,你的代码也不完整;它只会返回 Some("")因为take_while()将在第一个报价处停止,不会进一步扫描。您应该重写它以考虑初始报价。

关于debugging - Rust:如何在闭包参数中指定生命周期?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27213191/

相关文章:

swift - future 在 Swift 3 中的实现

scala - "Closures"是如何如此强大的抽象,以至于使用它来实现对象系统和基本控制结构?

c - 调试 C 代码

c++ - 为什么我可以使用 for 循环而不是单独访问 C++ map 元素?

c++ - 为什么我不能使用迭代器将 unique_ptr 从集合 move 到函数参数?

iterator - 为所有迭代器实现特征

validation - Groovy/Grails : How are constraints implemented?

c - 如何使用多维数组的指针访问内存?

php - 引用 - 这个错误在 PHP 中意味着什么?

c++ - 通过引用传递 C++ 迭代器有什么问题?