AVt天堂网 手机版,亚洲va久久久噜噜噜久久4399,天天综合亚洲色在线精品,亚洲一级Av无码毛片久久精品

當(dāng)前位置:首頁(yè) > 科技  > 軟件

太優(yōu)雅了!Rust 200 行代碼實(shí)現(xiàn)表達(dá)式解析

來(lái)源: 責(zé)編: 時(shí)間:2024-04-30 08:43:30 231觀看
導(dǎo)讀表達(dá)式解析、計(jì)算是一種基本和常見(jiàn)的任務(wù),例如最常見(jiàn)的算術(shù)表達(dá)式,計(jì)算的方法有很多,比如逆波蘭表達(dá)式、LL、LR 算法等等。這一次介紹一種最簡(jiǎn)單的、容易理解的基于運(yùn)算符優(yōu)先級(jí)的算法來(lái)完成這個(gè)任務(wù)。基于運(yùn)算符優(yōu)先級(jí)

表達(dá)式解析、計(jì)算是一種基本和常見(jiàn)的任務(wù),例如最常見(jiàn)的算術(shù)表達(dá)式,計(jì)算的方法有很多,比如逆波蘭表達(dá)式、LL、LR 算法等等。fKn28資訊網(wǎng)——每日最新資訊28at.com

這一次介紹一種最簡(jiǎn)單的、容易理解的基于運(yùn)算符優(yōu)先級(jí)的算法來(lái)完成這個(gè)任務(wù)。fKn28資訊網(wǎng)——每日最新資訊28at.com

基于運(yùn)算符優(yōu)先級(jí)的算法叫做 Precedence Climbing,它本質(zhì)上是一種遞歸下降解析表達(dá)式的方法,通過(guò)遞歸地處理運(yùn)算符和操作數(shù)來(lái)解析表達(dá)式,并根據(jù)運(yùn)算符的優(yōu)先級(jí)和結(jié)合性來(lái)確定表達(dá)式的計(jì)算順序。fKn28資訊網(wǎng)——每日最新資訊28at.com

這種算法的核心思想是利用運(yùn)算符的優(yōu)先級(jí)進(jìn)行“爬升”(Climbing),以決定表達(dá)式的結(jié)構(gòu)和計(jì)算順序。fKn28資訊網(wǎng)——每日最新資訊28at.com

首先我們做一些約束,由于運(yùn)算符眾多,我們可以支持幾種最常用的:fKn28資訊網(wǎng)——每日最新資訊28at.com

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

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

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

約定優(yōu)先級(jí)的主要作用是在計(jì)算的時(shí)候,需要根據(jù)優(yōu)先級(jí)來(lái)確定計(jì)算的順序。fKn28資訊網(wǎng)——每日最新資訊28at.com

確定了優(yōu)先級(jí)的問(wèn)題,第二個(gè)問(wèn)題是結(jié)合性,運(yùn)算符的結(jié)合性其實(shí)也是確定的,例如加法是左結(jié)合的,這意味著 2 + 3 + 4 等價(jià)于 (2 + 3) + 4,而冪運(yùn)算是右結(jié)合的,這意味著 2 ^ 3 ^ 4 實(shí)際上等價(jià)于 2 ^ (3 ^ 4)。fKn28資訊網(wǎng)——每日最新資訊28at.com

最后還需要注意一個(gè)問(wèn)題,那就是子表達(dá)式,也就是用括號(hào)包裹的部分,這部分實(shí)際上是需要單獨(dú)進(jìn)行計(jì)算的,并且比運(yùn)算符的優(yōu)先級(jí)更高。fKn28資訊網(wǎng)——每日最新資訊28at.com

其實(shí)也很容易理解,比如 2 * (3 + 5) * 7,盡管 * 的優(yōu)先級(jí)比 + 高,但是需要先計(jì)算括號(hào)內(nèi)的部分。fKn28資訊網(wǎng)——每日最新資訊28at.com

確定了這些需求,我們?cè)賮?lái)看如何用 Rust 代碼來(lái)進(jìn)行實(shí)現(xiàn)。fKn28資訊網(wǎng)——每日最新資訊28at.com

首先我們需要將表達(dá)式進(jìn)行解析,也就是詞法分析的階段,將一個(gè)表達(dá)式解析為不同的 Token,下面是約定的幾種 Token:fKn28資訊網(wǎng)——每日最新資訊28at.com

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

然后定義了一個(gè) Tokenizer 結(jié)構(gòu)體,主要是利用 Peekable 接口將表達(dá)式解析為不同的 Token:fKn28資訊網(wǎng)——每日最新資訊28at.com

// 將一個(gè)算術(shù)表達(dá)式解析成連續(xù)的 Token// 并通過(guò) Iterator 返回,也可以通過(guò) Peekable 接口獲取struct Tokenizer<'a> {    tokens: Peekable<Chars<'a>>,}

然后自定義實(shí)現(xiàn)了一個(gè) Iterator,讓解析后的 Token 可以通過(guò)迭代器進(jìn)行返回。fKn28資訊網(wǎng)——每日最新資訊28at.com

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

假如我們的表達(dá)式是 2 + 3 ^ 2 * 3 + 4,實(shí)際上解析后的 Token 就是:fKn28資訊網(wǎng)——每日最新資訊28at.com

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

拿到 Token 之后,進(jìn)入到了語(yǔ)法分析的階段,需要根據(jù)每個(gè)表達(dá)式的含義,以及其優(yōu)先級(jí),計(jì)算對(duì)應(yīng)的結(jié)果。fKn28資訊網(wǎng)——每日最新資訊28at.com

首先定義一個(gè)方法,計(jì)算單個(gè) Token 以及子表達(dá)式,這只存在兩種情況,分別是 Number 這個(gè) Token,以及帶括號(hào)的子表達(dá)式。fKn28資訊網(wǎng)——每日最新資訊28at.com

fn compute_atom(&mut self) -> Result<i32> {        match self.iter.peek() {            // 如果是數(shù)字的話,直接返回            Some(Token::Number(n)) => {                let val = *n;                self.iter.next();                return Ok(val);            }            // 如果是左括號(hào)的話,遞歸計(jì)算括號(hào)內(nèi)的值            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(),                ))            }        }    }

這里其實(shí)比較好理解,如果是 Number 直接返回,如果是子表達(dá)式,則重新調(diào)用計(jì)算表達(dá)式的方法進(jìn)行計(jì)算。fKn28資訊網(wǎng)——每日最新資訊28at.com

然后是另一個(gè)核心的方法計(jì)算表達(dá)式:fKn28資訊網(wǎng)——每日最新資訊28at.com

fn compute_expr(&mut self, min_prec: i32) -> Result<i32> {    // 計(jì)算第一個(gè) 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 一定是運(yùn)算符        // 2. Token 的優(yōu)先級(jí)必須大于等于 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();        // 遞歸計(jì)算右邊的表達(dá)式        let atom_rhs = self.compute_expr(next_prec)?;                // 得到了兩邊的值,進(jìn)行計(jì)算        match token.compute(atom_lhs, atom_rhs) {            Some(res) => atom_lhs = res,            None => return Err(ExprError::Parse("Unexpected expr".into())),        }    }    Ok(atom_lhs)}

這個(gè)方法中核心的邏輯可以分幾個(gè)步驟來(lái)理解:fKn28資訊網(wǎng)——每日最新資訊28at.com

一是使用了 min_prec 參數(shù)控制當(dāng)前層級(jí)的優(yōu)先級(jí),如果表達(dá)式的優(yōu)先級(jí)小于 min_prec 則直接跳出循環(huán),返回當(dāng)前的值。fKn28資訊網(wǎng)——每日最新資訊28at.com

比如 2 * 3 + 4,* 會(huì)先解析到,然后 + 運(yùn)算符的優(yōu)先級(jí)明顯比 * 更低,會(huì)直接返回當(dāng)前值 3。fKn28資訊網(wǎng)——每日最新資訊28at.com

二是如果運(yùn)算符的結(jié)合性是左邊的話,則下一次迭代的 min_prec 需要遞增。fKn28資訊網(wǎng)——每日最新資訊28at.com

比如表達(dá)式是 2 * 3 * 4,解析到第二個(gè) * 的時(shí)候,* 的優(yōu)先級(jí)本來(lái)是 2,但它是左結(jié)合的,所以此時(shí) min_prec 是 3,會(huì)直接跳出循環(huán),所以實(shí)際上會(huì)先計(jì)算 2 * 3。fKn28資訊網(wǎng)——每日最新資訊28at.com

最后是得到了運(yùn)算符兩邊的值,就可以進(jìn)行計(jì)算了,這里是根據(jù)運(yùn)算符的實(shí)際含義來(lái)進(jìn)行的:fKn28資訊網(wǎng)——每日最新資訊28at.com

// 根據(jù)當(dāng)前運(yùn)算符進(jìn)行計(jì)算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,    }}

這就是根據(jù)運(yùn)算符優(yōu)先級(jí)來(lái)進(jìn)行表達(dá)式計(jì)算的整體流程,這個(gè)算法看起來(lái)還是非常簡(jiǎn)潔優(yōu)雅的,非常巧妙的利用優(yōu)先級(jí)來(lái)解決運(yùn)算的順序和結(jié)合等問(wèn)題。fKn28資訊網(wǎng)——每日最新資訊28at.com

完整的代碼也只有 200 多行,比較適合用來(lái)練手,通過(guò)這個(gè)項(xiàng)目,可以學(xué)習(xí)到:fKn28資訊網(wǎng)——每日最新資訊28at.com

  • 一個(gè)優(yōu)雅、簡(jiǎn)潔的表達(dá)式計(jì)算的算法
  • 解決類似寫(xiě)一個(gè)計(jì)算器的面試問(wèn)題
  • Rust 基礎(chǔ)數(shù)據(jù)類型、枚舉、結(jié)構(gòu)體基本用法
  • 函數(shù)、遞歸
  • match 表達(dá)式
  • 自定義 Result 錯(cuò)誤處理
  • 迭代器的常見(jiàn)用法 next、peekable 等
  • 自定義迭代器
  • Option 使用

本文鏈接:http://www.tebozhan.com/showinfo-26-86686-0.html太優(yōu)雅了!Rust 200 行代碼實(shí)現(xiàn)表達(dá)式解析

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: 深入剖析:如何使用Pulsar和Arthas高效排查消息隊(duì)列延遲問(wèn)題

下一篇: C#實(shí)戰(zhàn):圖像清晰度增強(qiáng)介紹和案例實(shí)踐

標(biāo)簽:
  • 熱門焦點(diǎn)
  • 線程通訊的三種方法!通俗易懂

    線程通信是指多個(gè)線程之間通過(guò)某種機(jī)制進(jìn)行協(xié)調(diào)和交互,例如,線程等待和通知機(jī)制就是線程通訊的主要手段之一。 在 Java 中,線程等待和通知的實(shí)現(xiàn)手段有以下幾種方式:Object 類下
  • 只需五步,使用start.spring.io快速入門Spring編程

    步驟1打開(kāi)https://start.spring.io/,按照屏幕截圖中的內(nèi)容創(chuàng)建項(xiàng)目,添加 Spring Web 依賴項(xiàng),并單擊“生成”按鈕下載 .zip 文件,為下一步做準(zhǔn)備。請(qǐng)?jiān)谶M(jìn)入步驟2之前進(jìn)行解壓。圖
  • 電視息屏休眠仍有網(wǎng)絡(luò)上傳 愛(ài)奇藝被質(zhì)疑“薅消費(fèi)者羊毛”

    記者丨寧曉敏 見(jiàn)習(xí)生丨汗青出品丨鰲頭財(cái)經(jīng)(theSankei) 前不久,愛(ài)奇藝發(fā)布了一份亮眼的一季報(bào),不僅營(yíng)收和會(huì)員營(yíng)收創(chuàng)造歷史最佳表現(xiàn),其運(yùn)營(yíng)利潤(rùn)也連續(xù)6個(gè)月實(shí)現(xiàn)增長(zhǎng)。自去年年初
  • 一條抖音4億人圍觀 ! 這家MCN比無(wú)憂傳媒還野

    作者:Hiu 來(lái)源:互聯(lián)網(wǎng)品牌官01 擦邊少女空降熱搜,幕后推手曝光被網(wǎng)友譽(yù)為&ldquo;純欲天花板&rdquo;的女網(wǎng)紅井川里予,近期因?yàn)橐唤M哥特風(fēng)照片登上熱搜,引發(fā)了一場(chǎng)互聯(lián)網(wǎng)世界關(guān)于
  • 網(wǎng)紅炒股不為了賺錢,那就是耍流氓!

    來(lái)源:首席商業(yè)評(píng)論6月26日高調(diào)宣布入市,網(wǎng)絡(luò)名嘴大v胡錫進(jìn)居然進(jìn)軍了股市。在一次財(cái)經(jīng)媒體峰會(huì)上,幾個(gè)財(cái)經(jīng)圈媒體大佬就&ldquo;胡錫進(jìn)炒股是否知道認(rèn)真報(bào)道&rdquo;展開(kāi)討論。有
  • 華為HarmonyOS 4.0將于8月4日發(fā)布 或搭載AI大模型技術(shù)

    華為宣布HarmonyOS4.0將于8月4日正式發(fā)布。此前,華為已經(jīng)針對(duì)開(kāi)發(fā)者公布了HarmonyOS4.0,以便于開(kāi)發(fā)者提前進(jìn)行適配,也因此被曝光出了一些新系統(tǒng)的特性
  • iQOO Neo8系列今日官宣:首發(fā)天璣9200+ 全球安卓最強(qiáng)芯!

    在昨日舉行的的聯(lián)發(fā)科新一代旗艦芯片天璣9200+的發(fā)布會(huì)上,iQOO官方也正式宣布,全新的iQOO Neo8系列新品將全球首發(fā)搭載這款當(dāng)前性能最強(qiáng)大的移動(dòng)平臺(tái)
  • 榮耀Magicbook V 14 2021曙光藍(lán)版本正式開(kāi)售,擁有觸摸屏

    榮耀 Magicbook V 14 2021 曙光藍(lán)版本正式開(kāi)售,搭載 i7-11390H 處理器與 MX450 顯卡,配備 16GB 內(nèi)存與 512GB SSD,重 1.48kg,厚 14.5mm,具有 1.5mm 鍵盤鍵程、
  • 利用職權(quán)私自解除被封帳號(hào) Meta開(kāi)除20多名員工

    11月18日消息,據(jù)外媒援引知情人士表示,過(guò)去一年時(shí)間內(nèi),F(xiàn)acebook母公司Meta解雇或處罰了20多名員工以及合同工,指控這些人通過(guò)內(nèi)部系統(tǒng)以不當(dāng)方式重置用戶帳號(hào),其
Top