Skip to content

Rust 入门 #10

Open
Open
@wangshengfei

Description

@wangshengfei

Rust 是什么?

Rust 语言由 Mozilla 开发,最早发布于 2014 年 9 月。一门通用系统级编程语言。特点是高性能(系统级底层),高可靠性(内存安全)
Rust 可用于开发

  1. 命令行程序
  2. web 应用
  3. 网络服务器
  4. 嵌入式设备
  5. 机器人,区块链

https://www.rust-lang.org/zh-CN/

2021 Rust 行业报告
https://mp.weixin.qq.com/s/9rjeVgVzmrC0wWhV4wA9FA

Why Rust

  1. 大型前端项目的编译和构建,用 js 写的工具链等基础设施不能满足要求。
    swc(Rust)、esbuild(go)的出现,越来越多的框架倾向于选择非 JavaScript 的编译工具来实现提速,Babel 不再是此方向的唯一选择。未来前端相关的基础设施都可能被 Rust 重写。
    https://github.com/evanw/esbuild

  2. 安全性 https://new.qq.com/omn/20200723/20200723A06ATL00.html

  3. WebAssembly

安装

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

安装 rustup 工具链

判断是否正确的安装:

rustc --version

Hello World

  1. 新建一个 hello.rs
  2. 输入以下:
fn main() {
  println!("hello world!");
}
  1. rustc hello.rs
  2. 执行:./hello

使用 Cargo

Cargo 是 Rust 工具链中内置的构建系统和包管理工具

  1. cargo new hello2
  2. 进入目录,执行:cargo build(构建项目)
  3. cargo build
  4. 直接执行 debug 的二进制文件

cargo run(构建+运行)

常用命令

版本更新
rustup update

查看版本
cargo --version

构建项目
cargo build

运行项目
cargo run

测试项目
cargo test

为项目构建文档
cargo doc

将库发布到 crates.io
cargo publish

说明

  1. TOML 一种配置文件格式,类似 json,yaml https://github.com/toml-lang/toml
  2. dependencies 项目依赖
    需要用的包去 https://crates.io/ 找。类似 https://www.npmjs.com/ 。可自己发包。
    cargo new --lib

核心概念

所有权系统

内存

管理内存

C/C++:这样的语言主要通过手动方式管理内存,开发者需要手动的申请和释放内存资源。如果没有正确的释放内存,容易产生 bug。(malloc申请内存)

Java:JVM 具备自动回收内存资源的功能。但这种方式常常会降低运行时效率,所以 JVM 会尽可能少的回收资源,这样也会使程序占用较大的内存资源。(通过垃圾回收完成内存的自动管理)

使用了包含特定规则的所有权系统来管理内存,这套规则允许编译器在编译过程中执行检查工作,来识别内存安全的问题。

设计了一套语法机制,使用这种语法在编译阶段就能更有效地分析内存资源的有用性以实现内存管理

编程语言的世界观

一门编程语言的诞生,一定有它想解决的问题。而围绕着这个问题。

所有权规则

  1. Rust 中的每个值都有一个变量,作为它的所有者。
  2. 同一时间内,值有且仅有一个所有者
  3. 当所有者离开自己的作用域时,它持有的值就会被释放掉

例子:

{                   // 由于变量 s 还未被声明,所以它在这里是不可用的(如果访问,编译的时候就报错)
  let s = "hello";  // 从这里开始变量 s 变得可用 
                    // 执行与 s 相关的操作
}                   // 作用域到这里结束,变量 s 再次不可用(如果访问,编译的时候就报错)
  1. s 从进入作用域变得有效,
  2. 它会保持自己的有效性直到自己离开作用域为止

变量与数据交互的方式(数据传递)

js中值传递(基本数据类型)和引用传递(对象)

  1. 克隆(值传递)
  2. 移动

发生克隆的情况

  1. 栈上的数据
  2. 实现了 copy 的这种 trait 的数据类型(系统默认,u32,bool,char等类型实现了copy 的 trait)

trait 可以理解为接口。java 中的 interface。

发生移动的情况

  1. 堆上的数据
let x = 5;
let y = x;
println!("x = {}, y = {}",x, y); // 有效的

let x = String::from("hello");
let y = x
println!("x = {}", x); // 无效的
println!("y = {}", y); // 有效的

所有权与函数

fn main() {
    let s = String::from("hello");
    // s 被声明有效

    takes_ownership(s);
    // s 的值被当作参数传入函数
    // 所以可以当作 s 已经被移动,从这里开始已经无效(和js表现不一样)

    let x = 5;
    // x 被声明有效

    makes_copy(x);
    // x 的值被当作参数传入函数
    // 但 x 是基本类型,依然有效
    // 在这里依然可以使用 x 却不能使用 s

} // 函数结束, x 无效, 然后是 s. 但 s 已被移动, 所以不用被释放


fn takes_ownership(some_string: String) {
    // 一个 String 参数 some_string 传入,有效
    println!("{}", some_string);
} // 函数结束, 参数 some_string 在这里释放

fn makes_copy(some_integer: i32) {
    // 一个 i32 参数 some_integer 传入,有效
    println!("{}", some_integer);
} // 函数结束, 参数 some_integer 是基本类型, 无需释放

有返回值的情况

fn main() {
    let s1 = gives_ownership();
    // gives_ownership 移动它的返回值到 s1

    let s2 = String::from("hello");
    // s2 被声明有效

    let s3 = takes_and_gives_back(s2);
    // s2 被当作参数移动, s3 获得返回值所有权
} // s3 无效被释放, s2 被移动, s1 无效被释放.

fn gives_ownership() -> String {
    let some_string = String::from("hello");
    // some_string 被声明有效

    return some_string;
    // some_string 被当作返回值移动出函数
}

fn takes_and_gives_back(a_string: String) -> String { 
    // a_string 被声明有效

    a_string  // a_string 被当作返回值移出函数
}

有返回值的函数,会将返回值的所有权移动到调用函数的地方。(s3获得所有权)

引用与借用

如果想调用一个函数,还能继续使用 String 呢?

fn main() {
    let s1 = String::from("hello");

    let len = calculate_length(&s1);

    println!("The length of '{}' is {}.", s1, len); // 此时 s1 是有效的。如果上面一行不加「引用符号」&。那么 s1 就是无效的
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

「引用符号 &」
通过引用传递参数给函数的方法也被称为借用

默认是不可变引用。比如想要在 calculate_length 改变字符串的内容,是不会被允许的。需要

fn main() {
    let mut s = String::from("hello");
    // s 是可变的

    change(&mut s);
}
fn change(some_string: &mut String) {
  some_string.push_str("world");
}

引用规则:

  1. 在任何一段给定时间内,要么只能拥有一个可变引用,要么拥有任意数量的不可变引用。(原因:两个指针同时向同一空间写入数据会发生数据竞争,导致出错)
  2. 引用总是有效的

软件中缺陷

不同阶段和解决时间

  1. 不引入任何缺陷(理想情况) -- 无需解决时间
  2. 当敲下代码的那一刻,有缺陷的地方就能够被捕获到(language server,eslint,pritter) -- 秒级
  3. 编译期 or UT (Unit testing) 单元测试 -- 秒级到分钟级
  4. CI or code review 期间 -- 分钟 or 小时 or 天级(根据复杂度不同)
  5. 部署后研发或用户发现。 -- 天 or 月

早发现,早隔离,早诊断,早治疗

WebAssembly

概念

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

诞生
C++ 经过 Emscripten 编译成字节码,字节码编译成 js
游戏改成 js 性能低,有了 asm.js
浏览器原生支持 WebAssembly

Rust-Proportion

http://webassembly.org.cn/
https://developer.mozilla.org/zh-CN/docs/WebAssembly

现状
https://blog.scottlogic.com/2021/06/21/state-of-wasm.html

Rust 和 WebAssembly

有两大主要使用场景
https://developer.mozilla.org/zh-CN/docs/WebAssembly/Rust_to_wasm

  1. 构建完整应用 —— 整个 Web 应用都基于 Rust 开发!(例子 https://github.com/sheshbabu/rustmart-yew-example)
  2. 构建应用的组成部分 —— 在现存的 JavaScript 前端中使用 Rust

更好用的脚手架
https://github.com/lencx/vite-plugin-rsw

参考:
https://software-lab.org/publications/www2021.pdf

透过 Rust 探索系统的本原:编程语言
https://mp.weixin.qq.com/s?__biz=MzA3NDM0ODQwMw==&mid=2649828932&idx=1&sn=4a580c729ec39823d9d53ec65734ed3d

透过 Rust 探索系统的本原:内存管理
https://mp.weixin.qq.com/s/1juaadR3AqHa8H19sHWHmQ

十年磨一剑,WebAssembly 是如何诞生的?
https://mp.weixin.qq.com/s/rmvdVLeV049zcZs9dpTQ_A

遇到的问题
rustwasm/wasm-pack#705 (comment)

rustwasm/create-wasm-app#146

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions