繁体   English   中英

Rust:如何在闭包参数中指定生存期?

[英]Rust: How to specify lifetimes in closure arguments?

我正在编写一个解析器生成器作为学习锈的项目,并且遇到了一些我无法使用生存期和结束时间解决的问题。 这是我的简化情况(很抱歉,它是如此复杂,但是我需要在实际版本中使用自定义迭代器,这似乎对编译器的行为有所影响):

游戏围栏链接: 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函数中隐藏主生命周期(我在impl尝试过使用它的主生命周期,但是编译器抱怨'main get_chunk内部未定义get_chunk )。 我认为它仍然可以工作,因为调用后get_chunk将匹配'mainimpl'mainget_chunk ,但我不知道这是正确的。

第二个问题是,闭包内的&mut acc的生存期必须为'scan_literal ,才能像我希望的那样工作(在此示例中,直到第一个"为止,一直累积字符)。我无法添加显式生存期但是,对于&mut acc ,编译器表示其生存期仅限于闭包本身,因此我无法返回引用以在fold的下一次迭代中使用。我已经获得了以各种其他方式进行编译和运行的函数,但我不明白这里是什么问题。

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

首先,关于一生。 在其他函数内部定义的函数是静态的,它们不以任何方式与其外部代码连接。 因此,它们的寿命参数是完全独立的。 您不希望将'main用作get_chunk()的生命周期参数,因为它会get_chunk()外部的'main生命周期,并且只会造成混乱。

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

|&mut acc, chr| ...

很有可能不是您真正认为的那样。 闭包/函数参数允许使用不可辩驳的模式,并且&在模式中具有特殊含义。 即,它取消引用与之匹配的值,并将其标识符分配给该取消引用的值:

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

你能想到的&在一个图案作为相反&中的表达式:在表达它的意思是“需要参考”,在它的意思是“删除引用”的图案。

但是mut不属于&在模式中; 它属于标识符,表示具有该标识符的变量是可变的,即您不应写

|&mut acc, chr| ...

|& mut acc, chr| ...

您可能对该RFC感兴趣,而该RFC恰恰与此语言语法方面的问题有关。

看来您想做一件非常奇怪的事情,我不确定我了解您的去向。 您很可能混淆不同的字符串类型。 首先,您应该阅读解释所有权和借用以及何时使用它们的官方指南 (您可能还想阅读未完成的所有权指南 ;它将很快进入主文档树),然后您应该阅读字符串指南。

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

#[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();
}

您不需要将外部引用传递到闭包中。 您可以直接在fold()操作中生成一个String 我还简化了您的代码,使其更加惯用。

请注意,现在impl for Scanner也可以与返回&str任意迭代器一起使用。 这很可能是你想写的不是这个专业Scanner只与工作MyIterGraphemes里面。 by_ref()操作将IIterator<T> &mut I转换为J ,其中JIterator<T> 即使您只有对原始迭代器的可变引用,它也允许迭代器的进一步链接。

顺便说一下,您的代码也不完整。 它只会返回Some("")因为take_while()会停在第一个引号上,并且不会进一步扫描。 您应该重写它以考虑初始报价。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM