如何从同一类型的另一个方法内部使用 &mut self 调用方法? [英] How to call method with &mut self from inside another method of the same type?

查看:41
本文介绍了如何从同一类型的另一个方法内部使用 &mut self 调用方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 Scanner 结构,它实现了一个 scan(&mut self) 方法.看起来像这样.

I've got a Scanner struct that has a scan(&mut self) method implemented. It looks like this.

pub struct Scanner {
    input: String,
    output: Vec<String>,
    state: ScannerState,
}

impl Scanner {
    pub fn scan(&mut self) {
        self.state = ScannerState::CharMode;
        for character in self.input.chars() {
            match character {
                i @ '0'...'9'   => self.output.push(format!("Integer digit: {}", i)),
                '+'             => self.output.push("Addition operator: +".to_string()),
                '-'             => self.output.push("Subtraction operator: -".to_string()),
                '*'             => self.output.push("Multiplication operator: *".to_string()),
                '/'             => self.output.push("Division operator: /".to_string()),
                '%'             => self.output.push("Modulus operator: %".to_string()),
                '^'             => self.output.push("Exponent operator: ^".to_string()),
                '='             => self.output.push("Assignment operator: =".to_string()),
                ';'             => self.output.push("Statement terminator: ;".to_string()),
                c @ 'a'...'z'| c @ 'A'...'Z'
                                => self.output.push(format!("Variable name: {}", c)),
                ' '             => self.output.push("Space, ignoring.".to_string()),
                z @ _           => self.output.push(format!("Unrecognized token: {}", z))
            }
        }
    }        
}

然而,正如您可能怀疑的那样,Scanner 的状态会发生变化,它需要在不同的状态下以不同的方式对待令牌.因此,从 scan() 方法本身内部调用 Scanner 上的私有方法会很有用,类似于:

However, as you might suspect, the state of the Scanner will change, and it will need to treat tokens differently in different states. Therefore, it would be useful to call a private method on the Scanner from within the scan() method itself, akin to this:

pub fn scan(&mut self) {
    self.state = ScannerState::CharMode;

    while self.state == ScannerState::CharMode {
        for character in self.input.chars() {
            self.char_match(character);
        }
        self.state = ScannerState::Done;
    }
}

fn char_match(&mut self, c: char) {
    match c {
        '+'             => self.output.push("Addition operator: +".to_string()),
        '-'             => self.output.push("Subtraction operator: -".to_string()),
        '*'             => self.output.push("Multiplication operator: *".to_string()),
        '/'             => self.output.push("Division operator: /".to_string()),
        '%'             => self.output.push("Modulus operator: %".to_string()),
        '^'             => self.output.push("Exponent operator: ^".to_string()),
        '='             => self.output.push("Assignment operator: =".to_string()),
        ';'             => self.output.push("Statement terminator: ;".to_string()),
        ' '             => self.output.push("Space, ignoring.".to_string()),
        'q'             => self.state = ScannerState::QuitMode,
        i @ '0'...'9'   => self.output.push(format!("Integer digit: {}", i)),
        c @ 'a'...'z'   => self.output.push(format!("Variable name: {}", c)),
        z @ _           => self.output.push(format!("Unrecognized token: {}", z))
    }
}

等等!我们不能这样做,Rust 告诉我们:

But wait! We can't do that, Rust tells us:

src/scanner.rs:34:17: 34:21 error: cannot borrow `*self` as mutable because `self.input` is also borrowed as immutable
src/scanner.rs:34                 self.char_match(character);
                                  ^~~~

然而我们的 char_match() 方法需要有一个对 self 的可变引用,因为它推送,并且 push()Vec 需要可变性.那么我的问题是,根据前面的知识,纠正这种情况的理想方法是什么?

Yet our char_match() method NEEDS to have a mutable reference to self, since it pushes, and push()ing on a Vec requires mutability. My question then, is given the preceding knowledge, what is the ideal way to remedy this situation?

我是否只需要将 scan() 写成一个很长的方法?

Will I simply have to write scan() as a long method?

推荐答案

我的建议是让 char_match 无状态:

My suggestion would be to make char_match stateless:

pub fn scan(&mut self) {
    self.state = ScannerState::CharMode;

    while self.state == ScannerState::CharMode {
        for character in self.input.chars() {
            match char_match(character) {
                Some(string) => self.output.push(string),
                None => self.state = ScannerState::QuitMode
            }
        }
        self.state = ScannerState::Done;
    }
}

fn char_match(c: char) -> Option<String> {
    Some(match c {
        '+' => "Addition operator: +".into(),
        '-' => "Subtraction operator: -".into(),
        '*' => "Multiplication operator: *".into(),
        '/' => "Division operator: /".into(),
        '%' => "Modulus operator: %".into(),
        '^' => "Exponent operator: ^".into(),
        '=' => "Assignment operator: =".into(),
        ';' => "Statement terminator: ;".into(),
        ' ' => "Space, ignoring.".into(),

        'q' => return None,

        i @ '0'...'9' => format!("Integer digit: {}", i),
        c @ 'a'...'z' => format!("Variable name: {}", c),
        z @ _         => format!("Unrecognized token: {}", z)
    })
}

这完全避免了借用,并且也更加可组合.

This avoids borrowing altogether, and is also more composable.

这篇关于如何从同一类型的另一个方法内部使用 &amp;mut self 调用方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆