当前位置: 首页 > news >正文

怎么做网站中英文版本通江县网站建设

怎么做网站中英文版本,通江县网站建设,品牌设计机构公司,桂林生活网租房这是一个使用Rust实现的轻量化文本编辑器。学过Rust的都知道,Rust 从入门到实践中间还隔着好几个Go语言的难度,因此,如果你也正在学习Rust,那么恭喜你,这个项目被你捡到了。本项目内容较多,大概会分三期左右陆续发布&a…
  • 这是一个使用Rust实现的轻量化文本编辑器。
  • 学过Rust的都知道,Rust 从入门到实践中间还隔着好几个Go语言的难度,因此,如果你也正在学习Rust,那么恭喜你,这个项目被你捡到了。
  • 本项目内容较多,大概会分三期左右陆续发布,欢迎关注!

1. 第一篇

本系列教程默认你已经配置了Rust开发环境并具有一定的rust基础。所以直接从项目创建开始讲解;

使用下面的命令创建项目

  • 项目创建
cargo new xed
  • 运行程序
cargo run

如果成功输出Hello World表示项目基本功能正常,本章节完!


2. 第二篇

2.1 读取用户输入

现在修改main.rs,尝试读取用户的输入,你可以随时按下Ctrl + c终止程序;

use std::io;
use std::io::Read;
fn main() {let mut buf = [0; 1];while io::stdin().read(&mut buf).expect("Failed to read line") == 1 {}
}
  • 这里的内容不多,主要涉及到io的基本操作,所以导包是必要的;
  • 第4行创建了一个可变的buf数组,长度为1,初始值为0;
  • io::stdin().read(&mut buf) 尝试从标准输入流中读取数据,并将其存储在 buf 中。read 方法返回一个 Result 类型,其中包含读取的字节数或一个错误。
  • 所以expect("Failed to read line") 用于处理可能出现的错误情况。如果读取失败,程序将打印出 “Failed to read line” 作为错误信息并终止程序。
  • 最后的==1检查读取的字节数是否为1,否则结束循环;

2.2 实现q命令

本小节实现基本功能:用户输入q按下回车执行退出程序的操作。

use std::io;
use std::io::Read;
fn main() {let mut buf = [0; 1];while io::stdin().read(&mut buf).expect("Failed to read line") == 1 && buf !=[b'q'] {}
}
  • 程序会检查buf中输入的每一个字符,如果与q相同,就会结束程序;

在 Rust 中,[b'q'] 是一个字节字符串字面量,表示一个包含单个字节 q 的字节数组。

  1. [b'q']

    • b'q' 是 Rust 中的字节字面量,表示一个字节,即 ASCII 字符 'q' 对应的字节值。
    • 在 Rust 中,使用 b 前缀可以将字符转换为对应的字节值。这种表示方式常用于处理字节数据。
  2. 字节值和字符映射:

    • 在 ASCII 编码中,每个字符都有一个对应的字节值。在 ASCII 编码中,字符 'q' 对应的字节值是 113
    • 使用 b'q' 可以直接表示这个字节值,而 [b'q'] 则将这个字节值包装在一个长度为 1 的字节数组中。

因此,[b'q'] 表示一个包含单个字节值为 113(即 ASCII 字符 'q' 对应的字节值)的字节数组。在上下文中,buf != [b'q'] 的条件判断将检查 buf 中存储的字节是否不等于 'q' 对应的字节值,即检查输入的数据是否不是 'q'

  • 等价写法:buf[0] != b'q'

2.3 常规模式与原始模式

上面的情况就是常规模式,也就是程序启动后终端可以正常监听并回显你输入的内容;

而这里说的原始模式的作用和常规模式相反,我们这里可以直接使用crossterm库来实现,添加依赖:

cargo add crossterm
use std::io;
use std::io::Read;
use crossterm::terminal; // 添加依赖
fn main() {terminal::enable_raw_mode().expect("Could not run on Raw mode"); // 开启原始模式let mut buf = [0; 1];while io::stdin().read(&mut buf).expect("Failed to read line") == 1 && buf != [b'q'] {}
}

现在如果你运行程序,你的输入在终端并没有任何回显,并且当你输入q的时候也是直接无提示的退出程序,这就是crossterm帮我们实现的原始模式的基本功能;

如果要禁用原始模式,考虑下面的代码,最后一行就是禁用这个模式的逻辑;

use crossterm::terminal; /* add this line */
use std::io;
use std::io::Read;
fn main() {terminal::enable_raw_mode().expect("Could not turn on Raw mode");let mut buf = [0; 1];while io::stdin().read(&mut buf).expect("Failed to read line") == 1 && buf != [b'q'] {}terminal::disable_raw_mode().expect("Could not turn off raw mode"); /* add this line */
}

但是这样运行后会出现一个错误:

当在 terminal::enable_raw_mode() 之后的函数中发生错误并导致 panic 时,disable_raw_mode() 将不会被调用,导致终端保持在原始模式。这种情况可能会导致程序结束时终端状态不正确,用户体验受到影响。

所以为了解决这个问题,让我们创建 一个 名为 CleanUpstruct;

struct CleanUp;impl Drop for CleanUp {fn drop(&mut self) {terminal::disable_raw_mode().expect("Could not disable raw mode");}
}

然后修改原来的代码:

use crossterm::terminal; // 添加依赖
use std::io;
use std::io::Read;
struct CleanUp;impl Drop for CleanUp {fn drop(&mut self) {terminal::disable_raw_mode().expect("Could not disable raw mode");}
}fn main() {let _clean_up = CleanUp; // 看这里terminal::enable_raw_modde().expect("Could not run on Raw mode"); // 开启原始模式let mut buf = [0; 1];while io::stdin().read(&mut buf).expect("Failed to read line") == 1 && buf != [b'q'] {}// terminal::disable_raw_mode().expect("Could not turn off raw mode"); /* add this line */panic!(""); // 看这里
}
  • 现在我们新增了一个struct并实现了Drop这个trait;此时drop()函数会在我们的struct实例,也就是_clean_up超出作用域或者该实例出现panic时候执行;

  • 一旦上面的情况发生,drop()被执行,那么将成功禁用原始模式;

但是现在还有问题,此时使用Ctrl +c 无法退出程序;不妨看看当我们按下这些按键的时候输出了什么东西;

fn main() {let _clean_up = CleanUp;terminal::enable_raw_mode().expect("Could not run on Raw mode"); // 开启原始模式let mut buf = [0; 1];while io::stdin().read(&mut buf).expect("Failed to read line") == 1 && buf != [b'q'] {let character = buf[0] as char;if character.is_control() {println!("{}\r", character as u8)} else {println!("{}\r", character)}}
}
  • is_control()判断按下的是否为控制键位,在正常情况下,控制键位输入的字符我们并不需要;
  • ASCII的0-31都是控制字符,127也是;
  • 所以32-126就是可打印的字符,也是我们在编辑文本时需要进行输入回显的;
  • 另外,请注意我们在打印信息的时候使用的是\r而不是\n;此时我们在终端输入数据之后,光标会自动调整到屏幕的左侧。

现在请运行程序并尝试按下控制键位,例如方向键、 或 Escape 、 或 Page Up Page DownHome End Backspace DeleteEnter 或 。尝试使用 Ctrl 组合键,如 Ctrl-A、Ctrl-B 等。你会发现:

  • 方向键:Page Up、Page Down、Home 和 End 都向终端输入 3 或 4 个字节: 27 、、 '[' ,然后是一两个其他字符。这称为转义序列。所有转义序列都以 27 字节开头。按 Escape 键发送单个 27 字节作为输入。

  • Backspace 是字节 127 。Delete 是一个 4 字节的转义序列。

  • Enter 是 byte 10 ,这是一个换行符,也称为 '\n' 或 byte 13 ,这是回车符,也称为 \r

  • 另外:Ctrl-A 1 Ctrl-B2 Ctrl-C3…这确实有效的 将Ctrl 组合键将字母 A-Z 映射到代码 1-26

通过上面的步骤,我们基本了解了按键是如何转为字节的。


2.4 crossterm提供的事件抽象

crossterm 还提供了对各种关键事件的抽象,因此我们不必记住上面那一堆映射关系;而是使用这个crate带来的实现方法;

下面是使用这些抽象重构之火的main.rs:

use crossterm::event::{Event, KeyCode, KeyEvent};
use crossterm::{event, terminal}; // 添加依赖
use std::io;
use std::io::Read;
struct CleanUp;impl Drop for CleanUp {fn drop(&mut self) {terminal::disable_raw_mode().expect("Could not disable raw mode");}
}fn main() {let _clean_up = CleanUp;terminal::enable_raw_mode().expect("Could not run on Raw mode"); // 开启原始模式let mut buf = [0; 1];// 从这里开始重构loop {if let Event::Key(event) = event::read().expect("Failed to read line") {match event {KeyEvent {code: KeyCode::Char('q'),modifiers: event::KeyModifiers::NONE,kind: event::KeyEventKind::Press,state: event::KeyEventState::NONE,} => break,_ => {// todo}}println!("{:?}\r", event);};}
}
  • Event 是一个 enum 。由于我们目前只对按键感兴趣,因此我们检查返回的 Event 键是否为 Key .然后,我们检查按下的键是否为 q 。如果用户按下 q ,我们就会中断 loop ,程序将终止。
  • 当然,枚举中其他几个字段也是必须的,参考下文档中枚举的定义如下:
pub struct KeyEvent {pub code: KeyCode,pub modifiers: KeyModifiers,pub kind: KeyEventKind,pub state: KeyEventState,
}

其中的kind也是枚举:

pub enum KeyEventKind {Press,Repeat,Release,
}

sate的定义:

    pub struct KeyEventState: u8 {/// The key event origins from the keypad.const KEYPAD = 0b0000_0001;/// Caps Lock was enabled for this key event.////// **Note:** this is set for the initial press of Caps Lock itself.const CAPS_LOCK = 0b0000_1000;/// Num Lock was enabled for this key event.////// **Note:** this is set for the initial press of Num Lock itself.const NUM_LOCK = 0b0000_1000;const NONE = 0b0000_0000;}

看着有点怕但是不要怕,当下只需要理解代码中按下q执行程序退出的逻辑就可以。

下面是一个示例输出,它会在你按下按键的时候记录并打印相关的事件信息。你可以测试一下按下q是否正常退出程序。

image-20240514221935305


2.4 超时处理

现在的情况是,read()会无限期的在等待我们的键盘输入后返回。如果我们一直没有输入,那它就已知等待,这是个问题。因此我们需要有一个超时处理的逻辑,比如超过一定时间没用户没有任何操作就执行超时对应的处理逻辑。

use crossterm::event::{Event, KeyCode, KeyEvent};
use crossterm::{event, terminal}; // 添加依赖
use std::io;
use std::io::Read;
use std::time::Duration; // 新增依赖
struct CleanUp;impl Drop for CleanUp {fn drop(&mut self) {terminal::disable_raw_mode().expect("Could not disable raw mode");}
}fn main() {let _clean_up = CleanUp;terminal::enable_raw_mode().expect("Could not run on Raw mode"); // 开启原始模式let mut buf = [0; 1];// 从这里开始重构loop {if event::poll(Duration::from_millis(500)).expect("Program timed out") { // 超时处理if let Event::Key(event) = event::read().expect("Failed to read line") {match event {KeyEvent {code: KeyCode::Char('q'),modifiers: event::KeyModifiers::NONE,kind: event::KeyEventKind::Press,state: event::KeyEventState::NONE,} => break,_ => {// todo}}println!("{:?}\r", event);};}}
}

上面的代码中新增的超时处理中用到了crossterm::event::poll这个方法,如果在给定时间内没有 Event 可用, poll 则返回 false ,具体的函数定义信息如下:

image-20240515084930391


2.5 错误处理

一路走来,我们对程序的错误处理都是使用expect()进行简单的捕获,这显然并不是一个很好的选择和习惯,下面通过使用Result来对错误进行进一步的处理,修改main.rs:

use crossterm::event::{Event, KeyCode, KeyEvent};
use crossterm::{event, terminal};
use std::time::Duration; /* add this line */struct CleanUp;impl Drop for CleanUp {fn drop(&mut self) {terminal::disable_raw_mode().expect("Unable to disable raw mode")}
}fn main() -> std::result::Result<(), std::io::Error> {let _clean_up = CleanUp;terminal::enable_raw_mode()?;loop {if event::poll(Duration::from_millis(500))? {if let Event::Key(event) = event::read()? {match event {KeyEvent {code: KeyCode::Char('q'),modifiers: event::KeyModifiers::NONE,kind: _,state: _,} => break,_ => {//todo}}println!("{:?}\r", event);};} else {println!("No input yet\r");}}Ok(())
}

修改部分如下,注意,对于main方法本身也是指定了返回值类型,这在下面的贴图中没有展现。

image-20240515090210813

  • ? 算符只能用于返回 Result 的方法中,因此 Option 我们必须修改 our main() 以返回 Result .可以 crossterm::Result<T> 扩展为 std::result::Result<T, std::io::Error>

  • 因此,对于我们的 main() 函数,返回类型可以转换为 std::result::Result<(), std::io::Error>

本期完,下期内容抢先知:

  • Ctrl+Q退出
  • 键盘输入重构
  • 屏幕清理
  • 光标定位
  • 退出清屏
  • 波浪号占位符(类似于vim)
  • 追加缓冲区

写在最后:

如果这篇内容跟下来,你还是觉得比较难,那么我推荐你暂时放一下,这里推荐一个我之前写的开源项目untools,这也是一个使用Rust编写的工具库,可以拿来练手,顺手点个star的同时也欢迎有想法有能力的同学PR;
在这里插入图片描述

http://www.yayakq.cn/news/62899/

相关文章:

  • 做视频网站带宽中企动力洛阳分公司
  • 吧网站做软件的软件浙江温州乐清
  • 织梦网站怎样入侵做网站的服务器还需要空间吗
  • 网站内容体系网站备案主体黑名单
  • 最简单的网站开发软件程序开发是什么专业
  • 网站的基本组成部分有哪些内容北京网站建设小程序开发
  • 女生学网站建设好学吗wordpress快速清除本地图片
  • 北京规划建设 杂志 官方网站天津网站优化排名
  • 网站开发常用的流程建设厅网站进不去
  • cgi做的网站哈尔滨专门做网站
  • 做网站怎样赚到钱怎么做网站出肉狗
  • 个体工商户注册网站微信app下载安卓版官方下载
  • 邢台专业网站建设公司推荐手机模板素材图片
  • 网站建设代理网站杭州品牌网站建设推广
  • 成都网站建设找重庆最佳科技wordpress如何抓取
  • 网站建设在哪能看网站页面分析范文
  • 在线课程网站开发的研究意义短视频运营公司网站建设
  • 石家庄网站建设雨点牛微网站开发腾讯
  • 高端网站建站公司建设网站需要买什么手续费
  • 如何用dw建立网站网站建设网络公
  • 苏州网站建设找哪家建企业网站哪个平台好
  • 石家庄信息门户网站制作费用昆明网络科技公司有哪些
  • 在线免费网站建设百度做广告多少钱一天
  • 江苏网站建设哪家专业山东助企网站建设
  • 网站分别建网站做淘宝客可以吗
  • seo全站优化全案例wordpress封面图插件
  • 企业网站功能盐田区住房和建设局网站
  • 烟台百度做网站多少钱做网站直接从网上的icon吗
  • 广州响应式网站建设wordpress添加广告插件
  • 企业网站html模板下载企业网站手机端开发