日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

太優雅了!Rust 200 行代碼實現表達式解析

來源: 責編: 時間:2024-04-30 08:43:30 324觀看
導讀表達式解析、計算是一種基本和常見的任務,例如最常見的算術表達式,計算的方法有很多,比如逆波蘭表達式、LL、LR 算法等等。這一次介紹一種最簡單的、容易理解的基于運算符優先級的算法來完成這個任務。基于運算符優先級

表達式解析、計算是一種基本和常見的任務,例如最常見的算術表達式,計算的方法有很多,比如逆波蘭表達式、LL、LR 算法等等。eeB28資訊網——每日最新資訊28at.com

這一次介紹一種最簡單的、容易理解的基于運算符優先級的算法來完成這個任務。eeB28資訊網——每日最新資訊28at.com

基于運算符優先級的算法叫做 Precedence Climbing,它本質上是一種遞歸下降解析表達式的方法,通過遞歸地處理運算符和操作數來解析表達式,并根據運算符的優先級和結合性來確定表達式的計算順序。eeB28資訊網——每日最新資訊28at.com

這種算法的核心思想是利用運算符的優先級進行“爬升”(Climbing),以決定表達式的結構和計算順序。eeB28資訊網——每日最新資訊28at.com

首先我們做一些約束,由于運算符眾多,我們可以支持幾種最常用的:eeB28資訊網——每日最新資訊28at.com

  • + 加
  • - 減
  • * 乘
  • / 除
  • ^ 冪

并且我們知道,冪運算的優先級是最高的,其次是 * 和 /,優先級最低的是 + 和 -。所以約定其運算符的優先級分別為 3(^)、2(* /)、1(+ -)eeB28資訊網——每日最新資訊28at.com

2 + 3 ^ 2 * 3 + 4|---------------|   : prec 1    |-------|       : prec 2    |---|           : prec 3

約定優先級的主要作用是在計算的時候,需要根據優先級來確定計算的順序。eeB28資訊網——每日最新資訊28at.com

確定了優先級的問題,第二個問題是結合性,運算符的結合性其實也是確定的,例如加法是左結合的,這意味著 2 + 3 + 4 等價于 (2 + 3) + 4,而冪運算是右結合的,這意味著 2 ^ 3 ^ 4 實際上等價于 2 ^ (3 ^ 4)。eeB28資訊網——每日最新資訊28at.com

最后還需要注意一個問題,那就是子表達式,也就是用括號包裹的部分,這部分實際上是需要單獨進行計算的,并且比運算符的優先級更高。eeB28資訊網——每日最新資訊28at.com

其實也很容易理解,比如 2 * (3 + 5) * 7,盡管 * 的優先級比 + 高,但是需要先計算括號內的部分。eeB28資訊網——每日最新資訊28at.com

確定了這些需求,我們再來看如何用 Rust 代碼來進行實現。eeB28資訊網——每日最新資訊28at.com

首先我們需要將表達式進行解析,也就是詞法分析的階段,將一個表達式解析為不同的 Token,下面是約定的幾種 Token:eeB28資訊網——每日最新資訊28at.com

// Token 表示,數字、運算符號、括號#[derive(Debug, Clone, Copy)]enum Token {    Number(i32),    Plus,       // 加    Minus,      // 減    Multiply,   // 乘    Divide,     // 除    Power,      // 冪    LeftParen,  // 左括號    RightParen, // 右括號}

然后定義了一個 Tokenizer 結構體,主要是利用 Peekable 接口將表達式解析為不同的 Token:eeB28資訊網——每日最新資訊28at.com

// 將一個算術表達式解析成連續的 Token// 并通過 Iterator 返回,也可以通過 Peekable 接口獲取struct Tokenizer<'a> {    tokens: Peekable<Chars<'a>>,}

然后自定義實現了一個 Iterator,讓解析后的 Token 可以通過迭代器進行返回。eeB28資訊網——每日最新資訊28at.com

impl<'a> Iterator for Tokenizer<'a> {    type Item = Token;    fn next(&mut self) -> Option<Self::Item> {        // 消除前面的空格        self.consume_whitespace();        // 解析當前位置的 Token 類型        match self.tokens.peek() {            Some(c) if c.is_numeric() => self.scan_number(),            Some(_) => self.scan_operator(),            None => return None,        }    }}

假如我們的表達式是 2 + 3 ^ 2 * 3 + 4,實際上解析后的 Token 就是:eeB28資訊網——每日最新資訊28at.com

Token::Number(2)Token::PlusToken::Number(3)Token::PowerToken::Number(2)Token::MultiplyToken::Number(3)Token::PlusToken::Number(4)

拿到 Token 之后,進入到了語法分析的階段,需要根據每個表達式的含義,以及其優先級,計算對應的結果。eeB28資訊網——每日最新資訊28at.com

首先定義一個方法,計算單個 Token 以及子表達式,這只存在兩種情況,分別是 Number 這個 Token,以及帶括號的子表達式。eeB28資訊網——每日最新資訊28at.com

fn compute_atom(&mut self) -> Result<i32> {        match self.iter.peek() {            // 如果是數字的話,直接返回            Some(Token::Number(n)) => {                let val = *n;                self.iter.next();                return Ok(val);            }            // 如果是左括號的話,遞歸計算括號內的值            Some(Token::LeftParen) => {                self.iter.next();                let result = self.compute_expr(1)?;                match self.iter.next() {                    Some(Token::RightParen) => (),                    _ => return Err(ExprError::Parse("Unexpected character".into())),                }                return Ok(result);            }            _ => {                return Err(ExprError::Parse(                    "Expecting a number or left parenthesis".into(),                ))            }        }    }

這里其實比較好理解,如果是 Number 直接返回,如果是子表達式,則重新調用計算表達式的方法進行計算。eeB28資訊網——每日最新資訊28at.com

然后是另一個核心的方法計算表達式:eeB28資訊網——每日最新資訊28at.com

fn compute_expr(&mut self, min_prec: i32) -> Result<i32> {    // 計算第一個 Token    let mut atom_lhs = self.compute_atom()?;        loop {        let cur_token = self.iter.peek();        if cur_token.is_none() {            break;        }        let token = *cur_token.unwrap();        // 1. Token 一定是運算符        // 2. Token 的優先級必須大于等于 min_prec        if !token.is_operator() || token.precedence() < min_prec {            break;        }        let mut next_prec = token.precedence();        if token.assoc() == ASSOC_LEFT {            next_prec += 1;        }        self.iter.next();        // 遞歸計算右邊的表達式        let atom_rhs = self.compute_expr(next_prec)?;                // 得到了兩邊的值,進行計算        match token.compute(atom_lhs, atom_rhs) {            Some(res) => atom_lhs = res,            None => return Err(ExprError::Parse("Unexpected expr".into())),        }    }    Ok(atom_lhs)}

這個方法中核心的邏輯可以分幾個步驟來理解:eeB28資訊網——每日最新資訊28at.com

一是使用了 min_prec 參數控制當前層級的優先級,如果表達式的優先級小于 min_prec 則直接跳出循環,返回當前的值。eeB28資訊網——每日最新資訊28at.com

比如 2 * 3 + 4,* 會先解析到,然后 + 運算符的優先級明顯比 * 更低,會直接返回當前值 3。eeB28資訊網——每日最新資訊28at.com

二是如果運算符的結合性是左邊的話,則下一次迭代的 min_prec 需要遞增。eeB28資訊網——每日最新資訊28at.com

比如表達式是 2 * 3 * 4,解析到第二個 * 的時候,* 的優先級本來是 2,但它是左結合的,所以此時 min_prec 是 3,會直接跳出循環,所以實際上會先計算 2 * 3。eeB28資訊網——每日最新資訊28at.com

最后是得到了運算符兩邊的值,就可以進行計算了,這里是根據運算符的實際含義來進行的:eeB28資訊網——每日最新資訊28at.com

// 根據當前運算符進行計算fn compute(&self, l: i32, r: i32) -> Option<i32> {    match self {        Token::Plus => Some(l + r),        Token::Minus => Some(l - r),        Token::Multiply => Some(l * r),        Token::Divide => Some(l / r),        Token::Power => Some(l.pow(r as u32)),        _ => None,    }}

這就是根據運算符優先級來進行表達式計算的整體流程,這個算法看起來還是非常簡潔優雅的,非常巧妙的利用優先級來解決運算的順序和結合等問題。eeB28資訊網——每日最新資訊28at.com

完整的代碼也只有 200 多行,比較適合用來練手,通過這個項目,可以學習到:eeB28資訊網——每日最新資訊28at.com

  • 一個優雅、簡潔的表達式計算的算法
  • 解決類似寫一個計算器的面試問題
  • Rust 基礎數據類型、枚舉、結構體基本用法
  • 函數、遞歸
  • match 表達式
  • 自定義 Result 錯誤處理
  • 迭代器的常見用法 next、peekable 等
  • 自定義迭代器
  • Option 使用

本文鏈接:http://m.www897cc.com/showinfo-26-86686-0.html太優雅了!Rust 200 行代碼實現表達式解析

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 深入剖析:如何使用Pulsar和Arthas高效排查消息隊列延遲問題

下一篇: C#實戰:圖像清晰度增強介紹和案例實踐

標簽:
  • 熱門焦點
Top 日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不
亚洲欧美综合精品久久成人| 中文av一区特黄| 国产亚洲精品久久久久动| 国产一区二区三区久久久| 伊人成人开心激情综合网| 亚洲精品美女91| 亚洲综合精品四区| 久久亚洲欧洲| 欧美精选午夜久久久乱码6080| 国产精品成人一区二区三区夜夜夜| 国产一区二区三区黄视频| 亚洲激情影院| 亚洲中无吗在线| 久久综合网hezyo| 国产精品啊啊啊| 在线观看欧美日韩国产| 亚洲图片在线| 免费久久99精品国产自在现线| 国产精品二区在线| 一区精品在线播放| 亚洲伊人一本大道中文字幕| 另类av导航| 国产精品日韩在线观看| 亚洲激情视频| 性欧美8khd高清极品| 欧美丰满高潮xxxx喷水动漫| 国产精品一区二区久激情瑜伽| 在线精品福利| 亚洲欧美一区二区精品久久久| 欧美14一18处毛片| 国产欧美视频在线观看| 亚洲美女淫视频| 久久亚洲一区| 国产精品日韩精品欧美在线| 亚洲国内在线| 久久久久高清| 国产精品国产三级国产| 亚洲国内高清视频| 久久精品夜色噜噜亚洲a∨| 欧美色图首页| 亚洲国产视频一区| 久久精品在这里| 国产精品欧美日韩一区| 亚洲精品一区二区三区av| 久久久久国产一区二区三区| 国产精品国产亚洲精品看不卡15 | 亚洲三级免费电影| 久久精品一区| 国产麻豆一精品一av一免费| 99综合精品| 欧美精品久久99久久在免费线| 国内外成人免费激情在线视频网站| 亚洲小视频在线观看| 欧美激情视频一区二区三区在线播放 | 欧美吻胸吃奶大尺度电影| 亚洲国产日韩欧美在线图片| 久久久99久久精品女同性| 国产精自产拍久久久久久蜜| 一区二区三区免费看| 欧美极品色图| 亚洲人成亚洲人成在线观看| 久久亚洲精品欧美| 国内精品久久久久久久影视麻豆 | 国产精品亚洲一区| 亚洲一区二区在线免费观看视频 | 国产亚洲人成a一在线v站| 午夜精品国产精品大乳美女| 国产精品成人播放| 一区二区三区色| 欧美日韩精品一区视频| 亚洲精品在线三区| 欧美精品久久99久久在免费线| 亚洲欧洲视频在线| 欧美成人午夜视频| 亚洲欧洲日本在线| 欧美精品97| 日韩一二三区视频| 欧美日韩精品系列| 一本色道久久综合| 欧美视频一区二区| 亚洲性夜色噜噜噜7777| 国产精品乱子久久久久| 亚洲欧美日韩爽爽影院| 国产伦精品一区二区三区照片91 | 国产伦精品一区二区三区在线观看| 亚洲一区二区三区涩| 国产精品久久久久久妇女6080| 亚洲一区二区三区色| 国产精品女主播一区二区三区| 亚洲女同在线| 国产在线观看精品一区二区三区 | 香蕉成人久久| 国语自产精品视频在线看抢先版结局 | 亚洲韩国日本中文字幕| 欧美韩日精品| 一本色道**综合亚洲精品蜜桃冫| 欧美日韩在线高清| 亚洲自拍偷拍一区| 国产午夜精品全部视频在线播放| 久久久美女艺术照精彩视频福利播放 | 欧美日韩精品高清| 亚洲午夜未删减在线观看| 国产伦一区二区三区色一情| 久久国产精品99精品国产| 在线观看日韩国产| 欧美人与性动交α欧美精品济南到| 亚洲视频播放| 国产亚洲欧洲| 欧美国产日韩精品免费观看| 亚洲一卡二卡三卡四卡五卡| 国产精品私房写真福利视频| 久久久国产视频91| 亚洲精品一区二区在线观看| 国产精品久久久久久久久免费樱桃| 午夜精品国产精品大乳美女| 在线观看欧美黄色| 欧美日韩国产小视频在线观看| 亚洲欧美日韩精品久久奇米色影视| 国产一区二区在线观看免费播放| 蜜桃av一区二区| 中文久久乱码一区二区| 国产字幕视频一区二区| 欧美激情1区2区3区| 亚洲欧美一区二区原创| 在线免费观看日本一区| 欧美日韩免费一区| 欧美资源在线| 亚洲美女av在线播放| 国产人成精品一区二区三| 欧美91视频| 午夜精品福利在线| 亚洲国内高清视频| 国产欧美日韩一区二区三区在线| 欧美成人按摩| 欧美亚洲综合久久| 亚洲毛片网站| 国外成人在线| 国产精品久久久久久一区二区三区| 久久久欧美精品sm网站| 亚洲图片在区色| 亚洲国产精品123| 国产老女人精品毛片久久| 欧美激情亚洲一区| 久久国产欧美日韩精品| 亚洲视频一区| 亚洲高清免费| 国产乱人伦精品一区二区| 欧美区高清在线| 久久午夜羞羞影院免费观看| 亚洲女女女同性video| 亚洲欧洲在线播放| 激情成人在线视频| 国产精品免费看| 欧美精品一区二区视频 | 欧美日韩视频一区二区| 久久人人爽人人爽爽久久| 亚洲已满18点击进入久久| 亚洲人成毛片在线播放| 极品少妇一区二区三区精品视频| 国产精品vvv| 欧美久久婷婷综合色| 久久日韩粉嫩一区二区三区| 午夜精品视频在线| 中日韩高清电影网| 亚洲精品一区中文| 亚洲电影成人| 国模大胆一区二区三区| 国产精品视屏| 欧美视频一区在线观看| 欧美韩日一区| 久久手机精品视频| 欧美一级免费视频| 亚洲综合精品| 中文网丁香综合网| 亚洲精品四区| 亚洲国产精品热久久| 雨宫琴音一区二区在线| 国产一区二区高清不卡| 国产伦精品一区二区三区视频孕妇 | 亚洲欧美日韩综合一区| 欧美成人高清| 国产亚洲精品bt天堂精选| 夜夜爽www精品| 麻豆精品精华液| 亚洲电影免费观看高清完整版在线观看 | 亚洲一级在线观看| 亚洲激情视频在线| 欧美午夜宅男影院在线观看| 欧美精品一区二区三区在线看午夜| 欧美日韩成人在线视频| 中文av字幕一区| 亚洲精品一区二区网址| 一区免费在线| 国产精品不卡在线| 欧美中文字幕| 亚洲乱码国产乱码精品精可以看| 欧美日韩精品高清| 亚洲欧美一区二区原创| 国产拍揄自揄精品视频麻豆| 欧美成人中文字幕在线| 久久久久国产一区二区三区四区| 亚洲专区一区| 亚洲黄色精品| 亚洲国产成人精品久久久国产成人一区|