Rust語言之GoF設計模式: 直譯器Interpreter模式

banq 發表於 2022-09-26
設計模式 Go

直譯器模式是  一種設計模式,它指定如何評估語言中的句子。直譯器模式描述瞭如何為簡單語言定義語法。

如果一個問題經常發生並且需要很長的重複步驟來解決它,那麼問題例項可能會用一種簡單的語言來表達,並且直譯器物件可以透過解釋用這種簡單語言編寫的句子來解決它。
基本上,對於我們定義的任何型別的問題:


// Interpreter pattern

// Define simple DSL string literal, and parse & execute it.

pub fn interpreter() {
    Interpreter::parse_and_execute("3 Mew Waon !");
}

struct Interpreter;

impl Interpreter {
    fn parse_and_execute(s: &str) {
        if let Some(i) = s.find(' ') {
            let (num, word) = s.split_at(i); // => ("3", " Mew Waon !")
            let word = &word[1..]; // Trim first blank from `word`.
            let times = num.parse::<usize>().unwrap();
            for _ in 0..times {
                print!("{} ", word);
            }
            println!();
        }
    }
}


Rust的宏可以看成變種直譯器:
Rust 提供了一個強大的宏系統,允許超程式設計。宏看起來像函式,只是它們的名稱以! 結尾,但宏不是生成函式呼叫,而是擴充套件為與程式的其餘部分一起編譯的原始碼。但是,與 C 和其他語言中的宏不同,Rust 宏被擴充套件為抽象語法樹,而不是字串預處理,因此您不會遇到意外的優先順序錯誤。

宏是使用macro_rules!宏建立的:

//// 這是一個名為`say_hello`的簡單宏。
macro_rules! say_hello {
       // `()`表示該宏不需要引數。
    () => {
              // 該宏將展開為這個塊的內容。
        println!("Hello!");
    };
}

fn main() {
      // 這個呼叫將擴充套件為 `println!("Hello"); `
    say_hello!()
}


那麼為什麼宏有用呢?
  1. 不要重複自己。在很多情況下,您可能需要在多個地方使用不同型別的類似功能。通常,編寫宏是避免重複程式碼的有用方法。
  2. 特定領域的語言DSL。宏允許您為特定目的定義特殊語法。
  3. 可變介面。有時您想定義一個接受可變數量引數的介面。一個示例是println!可以採用任意數量的引數,具體取決於格式字串!


規則引擎 中規則的編寫執行也屬於一種直譯器模式