「Rust重写sqlite」REPL

「这是我参与11月更文挑战的第 7 天,活动详情查看:2021最后一次更文挑战


REPL

既然我们是以SQLite为模型,那么我们不妨试着照搬SQLite的样子,以方便用户使用。当你运行sqlite3 时,SQLite启动一个 读-执行-打印 的循环,又称:REPL

❯ sqlite3

SQLite version 3.32.3 2020-06-18 14:16:19
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> .databases
main:
sqlite> .dadada
Error: unknown command or invalid arguments:  "dadada". Enter ".help" for help
sqlite> .exit
复制代码

首先为了实现上述结果,这里要做出一些设计选择。由于这个项目的重点是研究和建立一个数据库,大部分开发精力集中于此,这意味着我不想花大部分时间重新发明轮子和编写CLI解释器或REPL逻辑。因此,对于这些,我决定利用已经开发的、有点成熟的第三方库来完成。不过也许在未来,如果有一些空闲时间,并且使用这些第三方库确实影响了应用程序的整体性能,我可以随时回来替换。

REPL的逻辑是非常直接:

一个无限循环中,打印一个提示,获得一个输入行,验证然后处理该行。

我决定使用 rustyline crate,它已经相当成熟,内存效率高,而且已经解决了很多我们必须处理的问题,甚至从用户体验方面来说,例如,实时提供提示和自动完成,这是一个非常好的功能。

因此,在正式编写代码前,你可以在Github上找到它。下面我将使用一个demo snippet,快速演示 rustyline 是如何通过一个简单的例子工作的:

首先,需要在你的 cargo.toml 中添加该依赖关系:

[dependencies]  
rustyline = "7.1.0"
复制代码

main.rs 中:

use rustyline::error::ReadlineError;
use rustyline::Editor;

fn main() {
    // 创建一个具有默认配置选项的编辑器
    let mut repl = Editor::<()>::new();
    // 加载了一个带有历史命令的文件。如果该文件不存在,它会创建一个
    if repl.load_history(".repl_history").is_err() {
        println!("No previous history.");
    }
    // 无限循环,一直卡在这里,直到用户终止程序
    loop {
	// 要求用户输入一个命令。你可以在这里添加任何你想要的东西作为前缀
        let readline = repl.readline(">> ");

        // readline返回一个结果。然后用匹配语句来过滤这个结果
        match readline {
            Ok(line) => {
                repl.add_history_entry(line.as_str());
                println!("Line: {}", line);
            },
            Err(ReadlineError::Interrupted) => {
                println!("CTRL-C");
                break
            },
            Err(ReadlineError::Eof) => {
                println!("CTRL-D");
                break
            },
            Err(err) => {
                println!("Error: {:?}", err);
                break
            }
        }
    }
    // 把命令保存到文件中。到现在为止,它们都储存在内存中
    repl.save_history(".repl_history").unwrap();
}
复制代码

就这样,有了上述代码,你就有了一个基本的REPL程序,开始开始运行。