正确设定Rust的生命周期和可变性期望

时间:2014-10-12 19:08:13

标签: rust lifetime

我对Rust很陌生,并且组织了一个小实验,让我对注释的理解完全脱离了水。这是使用rust-0.13.0-nightly编译的,并且是代码here的婴儿围栏版本。

该程序的主要功能是识别',它共同负责分配字符串实例以及函数' lex'。我确定代码有点傻,所以,除了让生命周期足够正确以进行编译之外,我还很乐意接受一些关于使这个惯用的指导。

#[deriving(Show)]
enum Token<'a> {
    Field(&'a std::string::String),
}

#[deriving(Show)]
struct LexerState<'a> {
    character: int,
    field: int,
    tokens: Vec<Token<'a>>,
    str_buf: &'a std::string::String,
}

// The goal with recognize is to:
//
//  * gather all A .. z into a temporary string buffer str_buf
//  * on ',', move buffer into a Field token
//  * store the completely extracted field in LexerState's tokens attribute
//
// I think I'm not understanding how to specify the lifetimes and mutability
// correctly.
fn recognize<'a, 'r>(c: char, ctx: &'r mut LexerState<'a>) -> &'r mut LexerState<'a> {
    match c {
        'A' ... 'z'  => {
            ctx.str_buf.push(c);
        },
        ',' => {
            ctx.tokens.push(Field(ctx.str_buf));
            ctx.field += 1;
            ctx.str_buf = &std::string::String::new();
        },
        _ => ()
    };
    ctx.character += 1;
    ctx
}

fn lex<'a, I, E>(it: &mut I)
                     -> LexerState<'a> where I: Iterator<Result<char, E>> {
    let mut ctx = LexerState { character: 0, field: 0,
                               tokens: Vec::new(), str_buf: &std::string::String::new() };
    for val in *it {
        let c:char = val.ok().expect("wtf");
        recognize(c, &mut ctx);
    }
    ctx
}

fn main() {
    let tokens = lex(&mut std::io::stdio::stdin().chars());
    println!("{}", tokens)
}

1 个答案:

答案 0 :(得分:4)

在这种情况下,您构建新字符串而不是借用现有字符串,因此您可以直接使用拥有的字符串:

use std::mem;

#[deriving(Show)]
enum Token {
    Field(String),
}

#[deriving(Show)]
struct LexerState {
    character: int,
    field: int,
    tokens: Vec<Token>,
    str_buf: String,
}

// The goal with recognize is to:
//
//  * gather all A .. z into a temporary string buffer str_buf
//  * on ',', move buffer into a Field token
//  * store the completely extracted field in LexerState's tokens attribute
//
// I think I'm not understanding how to specify the lifetimes and mutability
// correctly.
fn recognize<'a, 'r>(c: char, ctx: &'r mut LexerState) -> &'r mut LexerState {
    match c {
        'A' ...'z' => { ctx.str_buf.push(c); }
        ',' => {
            ctx.tokens.push(Field(mem::replace(&mut ctx.str_buf,
                                               String::new())));
            ctx.field += 1;
        }
        _ => (),
    };
    ctx.character += 1;
    ctx
}

fn lex<I, E>(it: &mut I) -> LexerState where I: Iterator<Result<char, E>> {
    let mut ctx =
        LexerState{
            character: 0,
            field: 0,
            tokens: Vec::new(),
            str_buf: String::new(),
        };
    for val in *it {
        let c: char = val.ok().expect("wtf");
        recognize(c, &mut ctx);
    }
    ctx
}

fn main() {
    let tokens = lex(&mut std::io::stdio::stdin().chars());
    println!("{}" , tokens)
}