写点什么

魔改出一个 Encoder | Rust 学习笔记(一)

用户头像
李大狗
关注
发布于: 2021 年 02 月 25 日
魔改出一个 Encoder | Rust 学习笔记(一)

新年新目标


打算在 2021 年学习一门新的编程语言,Rust 是一个很好的标的,一方面它及其具备实用性;另一个方面它也能让我们在更高的层面上理解计算机。


本系列将是我从 Rust 小学生开始的 Rust 学习过程全记录。


话不多说,我们开整。


由于是一门新的语言(相对 Java),所以传统的到网上去找一本好的入门教材的方法失效了。


那我们就来康康 Rust 能做什么有趣的事情,有什么有趣的 Repo。


Substrate(Polkadot 公链)、Libra(Facebook 链)、WeDPR(FISCO BCOS 隐私保护组件)都是用 Rust 写的,不过评估一下,这些 Repo 的难度太高了,不适合用来作为语言入门。


后来发现 Rust 在 WebAssembly 方面目前进展很不错:


WebAssembly 是一种新的编码方式,可以在现代的网络浏览器中运行 - 它是一种低级的类汇编语言,具有紧凑的二进制格式,可以接近原生的性能运行,并为诸如 C / C ++等语言提供一个编译目标,以便它们可以在 Web 上运行。它也被设计为可以与 JavaScript 共存,允许两者一起工作。

>

## 简而言之

>

对于网络平台而言,WebAssembly 具有巨大的意义——它提供了一条途径,以使得以各种语言编写的代码都可以以接近原生的速度在 Web 中运行。在这种情况下,以前无法以此方式运行的客户端软件都将可以运行在 Web 中。



所以,Rust 的学习路线就这么定下来了,从 wasm 开始!


检索实例


既然确定了目标,那么可以开始检索相应的实例。这个实例有两个条件:


  • 光有文章是不行的,必须配套相应的的源码

  • 这个源码必须足够简洁,适合用来入门


经过一番检索,最后找到了这个:


项目代码:

https://github.com/RodionChachura/rust-js-snake-game/

运行地址:

https://rodionchachura.github.io/rust-js-snake-game/

教程地址:

https://geekrodion.com/blog/rustsnake


git clone 下来,运行了试试,的确可以。


但感觉不是我想要的,因为前端代码的内容太多了。


然后打开官方教程:


https://developer.mozilla.org/zh-CN/docs/WebAssembly/Rusttowasm


看到:


Rust 和 WebAssembly 有两大主要用例:

>

- 构建完整应用 —— 整个 Web 应用都基于 Rust 开发!

- 构建应用的组成部分 —— 在现存的 JavaScript 前端中使用 Rust。

>

目前,Rust 团队正专注于第二种用例,因此我们也将着重介绍它。对于第一种用例,可以参阅 yew 这类项目。


Yep,感觉我需要的是yew


Yew 的探索之旅


首先找到 yew的官网:


Yew is a modern Rust framework for creating multi-threaded front-end web apps with WebAssembly.

>

https://github.com/yewstack/yew


找到它官方的例子:


https://yew.rs/docs/zh-CN/getting-started/build-a-sample-app


结果,运行报错……


cargo-web is not compatible with web-sys.
复制代码


遇到问题,第一时间,当然是到官方 Repo 里去检索啦,然后就搜到这么一条 Issue:


https://github.com/yewstack/yew/issues/1081



建议使用 trunk,妥~


Trunk 的探索之旅


跳转到 Trunk Repo:


https://github.com/thedodd/trunk


发现里面有 examples,于是直接 clone 下来运行:



执行没问题,很好!


但是只有一个简单的实例,没法基于这个进行学习,怎么办?


我们回到 yew 的 Repo 里面,看下有没啥实例。


https://github.com/yewstack/yew/tree/master/examples


Examples 很多,也都能跑通,赞:



魔改出 Base64 Encoder!


在之前的编程课程里面,有一个编程要义我会经常提及:


在入门一个新的计算机技术的时候,千万不要一开始就从 0 到 1!因为从 0 到 1 的难度对新手来说太高。最开始应该先去魔改一个已有的项目。


我选择的是 todomvc,原始是长这样:



目的是把它修改成一个 Base64-Encoder:



Ok,那我们来看看原始代码:


......    fn view(&self) -> Html {        let hidden_class = if self.state.entries.is_empty() {            "hidden"        } else {            ""        };        html! {            <div class="todomvc-wrapper">                <section class="todoapp">                    <header class="header">                        <h1>{ "todos" }</h1>                        { self.view_input() }                    </header>                    <section class=classes!("main", hidden_class)>                        <input                            type="checkbox"                            class="toggle-all"                            id="toggle-all"                            checked=self.state.is_all_completed()                            onclick=self.link.callback(|_| Msg::ToggleAll)                        />                        <label for="toggle-all" />                        <ul class="todo-list">                            { for self.state.entries.iter().filter(|e| self.state.filter.fits(e)).enumerate().map(|e| self.view_entry(e)) }                        </ul>                    </section>                    <footer class=classes!("footer", hidden_class)>                        <span class="todo-count">                            <strong>{ self.state.total() }</strong>                            { " item(s) left" }                        </span>                        <ul class="filters">                            { for Filter::iter().map(|flt| self.view_filter(flt)) }                        </ul>                        <button class="clear-completed" onclick=self.link.callback(|_| Msg::ClearCompleted)>                            { format!("Clear completed ({})", self.state.total_completed()) }                        </button>                    </footer>                </section>                <footer class="info">                    <p>{ "Double-click to edit a todo" }</p>                    <p>{ "Written by " }<a href="https://github.com/DenisKolodin/" target="_blank">{ "Denis Kolodin" }</a></p>                    <p>{ "Part of " }<a href="http://todomvc.com/" target="_blank">{ "TodoMVC" }</a></p>                </footer>            </div>        }    }}......
复制代码


挺好,这个就是前端部分了,我们把它删减一下:


    fn view(&self) -> Html {        let hidden_class = if self.state.entries.is_empty() {            "hidden"        } else {            ""        };        html! {            <div class="todomvc-wrapper">                <h1>{ "encode/decode" }</h1>                { self.view_input() }                <section class=classes!("main", hidden_class)>                    <ul class="todo-list">                        { for self.state.entries.iter().filter(|e| self.state.filter.fits(e)).enumerate().map(|e| self.view_entry(e)) }                    </ul>                </section>            </div>        }    }
复制代码


我们可以看到,输入的逻辑在view_input()这个地方,于是我们找到那个函数:


fn view_input(&self) -> Html {        html! {            // You can use standard Rust comments. One line:            // <li></li>            <input                class="new-todo"          			// 改掉replaceholder                placeholder="What needs to be encode/decode?"                value=&self.state.value                oninput=self.link.callback(|e: InputData| Msg::Update(e.value))                onkeypress=self.link.batch_callback(|e: KeyboardEvent| {                    if e.key() == "Enter" { Some(Msg::Add) } else { None }                })            />            /* Or multiline:            <ul>                <li></li>            </ul>            */        }    }
复制代码


再找到Msg::Add


fn update(&mut self, msg: Self::Message) -> ShouldRender {        match msg {            Msg::Add => {                //info!("add things");                let description = self.state.value.trim();                let description_handled = format!("{}: {}", description, encode(description.to_string()));
if !description.is_empty() { let entry = Entry { description: description_handled, completed: false, editing: false, }; //info!("{}", entry.description); self.state.entries.push(entry); } self.state.value = "".to_string(); }......
复制代码


这个时候,我想先调试一下,因此需要把一些数据打印出来。


这个时候,首先想到的是print大法:


println!("Input: {}", val);
复制代码


但是,在trunk serve命令中,println!这个函数失效了!


trunkyew的 Repo 中进行检索,均未找到解决方案。


但是随即发现yew有 Discord Chatroom,于是乎进去搜索聊天记录。



Yummy,这里提到只要使用 wasm-logger 即可。


https://crates.io/crates/wasm-logger


在项目里添加wasm-logger


......// in the first of main.rs#[macro_use] extern crate log;......fn main() {		// init wasm logger!    wasm_logger::init(wasm_logger::Config::default());    yew::start_app::<Model>();}
复制代码


调用试试看:


fn update(&mut self, msg: Self::Message) -> ShouldRender {        match msg {            Msg::Add => {                info!("add things");......
复制代码


妥了!



接下来找到 Rust Base64 的库,调用之(修改的地方用 new 标出了):


......use base64::{encode, decode};......fn update(&mut self, msg: Self::Message) -> ShouldRender {        match msg {            Msg::Add => {                // new                info!("add things");                let description = self.state.value.trim();                // new                let description_handled = format!("{}: {}", description, encode(description.to_string()));
if !description.is_empty() { let entry = Entry { // new description: description_handled, completed: false, editing: false, }; // new info!("{}", entry.description); self.state.entries.push(entry); } self.state.value = "".to_string(); }
复制代码


运行之。


Okay,Base64-Encoder 就做好了!


效果:



Day1 的 Rust 学习就到这里了。


对了,Cargo.toml最后长这样:


[package]name = "encoder"version = "0.1.0"authors = ["Denis Kolodin <deniskolodin@gmail.com>"]edition = "2018"
[dependencies]strum = "0.20"strum_macros = "0.20"serde = "1"serde_derive = "1"yew = { path = "./packages/yew" }yew-services = { path = "./packages/yew-services" }
log = "0.4.6"wasm-logger = "0.2.0"base64 = "0.13.0"
复制代码





发布于: 2021 年 02 月 25 日阅读数: 37
用户头像

李大狗

关注

还未添加个人签名 2018.08.07 加入

还未添加个人简介

评论

发布
暂无评论
魔改出一个 Encoder | Rust 学习笔记(一)