Rust 101

Rust 101

Rust 入门,笔记,集合:vol 1

我学 《The Rust Programming Language》by Steve Klabnik and Carol Nichols, with contributions from the Rust Community。
伟大的开源中文译本:https://rustwiki.org/zh-CN/book/


Hello World

// hello.rs
fn main() {
   
    println!("Hello, world!");
}
$ rustc hello.rs
$ ./hello
Hello, world!

cargo:包管理、项目组织构建

$ cargo new hello_cargo  # 新建项目

$ cd hello_cargo
$ vim src/main.rs

$ cargo run    # 运行代码
$ cargo build  # 编译:debug
$ cargo build --release  # 编译:release

Rust 量

  • 常量:const 始终不可变
  • 变量:
    • let:默认不可变
    • let mut:只可变,类型不可变

遮蔽(shadow):作用域内重新声明同名变量。

  • 名不变
  • 值/类型可变
{
   
    let foo = 1;         # i64: 1
    let foo = 2.0;       # f64: 2.0
    {
   
        let foo = "3";   # &str: "3"
    }
                         # f64: 2.0
}

Rust 静态类型

静态类型:编译时确定所有变量的类型。


Rust 标量

类型 类型 说明
整型 i/u + sizei16u32,… * isize: 由机器架构决定(64 位机:isize=i64)
* usize: 用作索引值
浮点型 f32f64 默认 f64,IEEE 754 格式
布尔型 bool:`true false`
字符 char 4 byte:unicode

算术

+-*/%,…

整数 /:向下取整


整型:字面量
进制 字面量
0b1011
0o76
114_514
十六 0xfe
字节(u8) b'A'

整型:溢出
  • debug:panic
  • release:二进制补(正常溢出)or 其他可选行为

Rust 复合类型

元组 ()

let tup: (i32, f64, u8) = (500, 6.4, 1);`
  • 多种类型 多个值 放一起,长度固定
  • 解构:let (x, y, z) = tup;
  • 索引:let x = tup.0;
  • 单元类型:(),单元值:()
    • 表达式不返回 => return ();

数组 []

let a: [ i32 ;  5 ] = [1, 2, 3, 4, 5];
         类型   长度
  • 相同类型,长度固定
  • Repeat:let a = [3; 5]; => 5 个 3
  • 访问:let first = a[0];
    • 越界:runtime panic

Tips:用 dbg! 宏答应表达式的值到 stderr

let foo = dbg!(表达式);
           └──> 打印并返回值

Rust 函数

fn(,)-> 返回类型〕 {
   
    语句
    ...
    〔返回值表达式〕  // 可选,无则 return ()
}

注:六角括号 〔〕 表示内容可选


语句 vs 表达式

  • 语句:操作,不返回值
  • 表达式:计算,产生返回值
    • 函数、宏调用,代码块 { ... } 都是表达式

语句 = 表达式 + ;

let y = {
   
    let x = 3;
    x + 1         // 整个代码块值为 4 所以 y = 4
}

Rust 控制流

if 条件

if 表达式 {
              // 表达式必须返回 bool 值,不会隐式转换
    ...
} else if ... {
   
    ...
} else {
   
    ...
}

if 是表达式,有返回结果:

let num = if cond {
    5 } else {
    6 };

循环

  • loop:无限循环(可以 break 出来)
  • whilewhile 条件 { ... }
  • forfor element in array { ... }

break:退出并从循环返回值

let result = loop {
   
    counter += 1;
    if counter == 10 {
   
        break counter * 2;
    }
}

Range:

for n in (1..4).rev() {
     // .rev() 把 Range 反转
    ...
}

Rust 所有权

管理权(ownership)主要是管理堆数据

Rust 值的存放:

  • stack:编译时已知固定大小的数据
  • heap:编译时大小未知或不定的数据

所有权规则

  1. 每个值在任一时刻都有且只有一个所有者(owner)变量
  2. owner 离开作用域,值被丢弃(调用 drop 函数进行销毁)

移动 vs 克隆

栈值克隆:

let x = 5;
let y = 5;

// 栈中压入两个独立的 5 值
// 自动复制:一定是深拷贝

堆值移动:

let s1 = String::from("hello");
let s2 = s1;    // 值从 s1 移动到了 s2

// s1 不再可用:避免 double free
// Rust 没有浅拷贝:只移动,不拷贝

自动复制一定是运行时对性能影响小的深拷贝

要克隆堆值,必须使用显式的深拷贝:

let s1 = String::from("hi");
let s2 = s1.clone();

trait: Copy & Drop

实际上,起决定作用的并不是“栈值”、“堆值”,而是看类型实现了那种 trait(二选一):

  • Copy:可克隆

    let new = old;
    // 之后 old 仍可用
    
  • Drop:要移动

    离开作用域时,值被 drop

标量(整浮布字)都 impl 了 Copy;

元组所有元素 Copy,则元组 Copy;


所有权 & 函数

值传给函数:同赋值:

  • Copy 的复制
  • Drop 的移动:值移动到了 fn 里:外面(调用后面)不能用了
let i = 42;
let s = String::from("hi");

function(i, s);

println!("{}", i);  // ✅
println!("{}", s);  // ❌

引用、借用

引用:类似于 C 的指针

  • 引用:&
  • 解引用:*
let s = String::from("hi");
let l = len(&s);

fn len(s: &String) -> usize {
   
    s.len()  // == (*s).len()
}

借用:传 &s 不让函数拥有 s 的所有权

  • 函数 end,离开作用域 => 不 drop 值

可变引用
  • &s 只读引用
  • &mut s 可用于修改 s 的值
let mut s = String::from("hello ");
change(&mut s);    // 形实都要加 mut

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

同一时间,一个数据只能有多个只读引用一个可变引用

变 + 变 不变 + 变 不变 + 不变

=> (在编译时)避免(并发时) data race

let mut s = String::from("hi");

{
    let r0 = &mut s; }  // r0 离域,不再存在
let r1 = &mut s;      // ✅ r1 一个 &mut
let r2 = &mut s;      // ❌ r1、r2 两个 &mut

非词法作用域生命周期(Non-Lexical Lifetime,NLL)

引用的作用域是「声明 -> 最后一次使用」。

∴ 可以:

let ir = &s;
println!("{}", &ir);  // ir 不再使用:声明周期结束
let mr = &mut s;      // ✅
println!("{}", &mr);

悬垂引用

悬垂(dangling)引用:指向已释放的内存的引用。

=> Rust 直接编译时 Error

fn d() -> &String {
   
    let s = &String::from("hi");
    &s    // ❌ s 离开作用域即被 drop,&s 悬垂
}

slice

切片(slice):引用集合中的一段连续的元素。

let s = String::from("hello world");
let hello= &s[0..5];  // [0, 5)
// hello: &str => String 的 slice 是 &str
s.clear()  // ❌ 这个方法借 &mut s,
           //    但 hello 是借了个 immut
           //    immut + mut -> error

切片是一个不可变引用,结合“不能变+不变”的引用规则

=> 保证 slice 始终可用、未变。


字符串常量:

  • 类型: &str
  • 指向二进制程序中的某位置

一般处理字符串的函数都用 fn f(s: &str)

这样传参 String 对象和 &str (包括字面量)都可。


Rust struct

一般结构体

定义:

struct User {
   
    email: String
    age:   u8
}

实例化:

let mut foo = User {
   
    email: String::from("[email protected]"),
    age:   8,
};

println!("{}", foo.email);
foo.email = String::from("[email protected]");

语法糖:变量名与字段同名 => 简写

{foo: foo, } => {foo, }

fn build_user(email: String, age: u8) -> User {
   
    User {
   
        email,
        age,
    }
}

结构体更新语法

let user2 = User {
   
    email: String::from("[email protected]"),
    ..user1,    // 除了显式写的 email 字段,其余用 user1 的值
}
  • user1 中的 Drop 值被 user2 使用,则等于移动到了 user2user1 不再可用;
  • ..user1 只用了 user1 中的 Copy 值,则之后 user1 仍然可用:
    • User 中全是 Copy
    • 或 Drop 值全被显式给出

元组结构体

元组结构体:无字段名,匿名结构体。

struct Color(
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值