赞
踩
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.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
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
}
静态类型:编译时确定所有变量的类型。
类型 | 类型 | 说明 |
---|---|---|
整型 | i/u + size :i16 ,u32 ,… |
* isize : 由机器架构决定(64 位机:isize=i64 )* usize : 用作索引值 |
浮点型 | f32 ,f64 |
默认 f64 ,IEEE 754 格式 |
布尔型 | bool :`true |
false` |
字符 | char |
4 byte:unicode |
+
,-
,*
,/
,%
,…
整数
/
:向下取整
进制 | 字面量 |
---|---|
二 | 0b1011 |
八 | 0o76 |
十 | 114_514 |
十六 | 0xfe |
字节(u8) | b'A' |
元组 ()
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];
类型 长度
let a = [3; 5];
=> 5 个 3let first = a[0];
Tips:用 dbg!
宏答应表达式的值到 stderr
let foo = dbg!(表达式);
└──> 打印并返回值
fn 名(参, 数) 〔-> 返回类型〕 {
语句
...
〔返回值表达式〕 // 可选,无则 return ()
}
注:六角括号 〔〕
表示内容可选
{ ... }
都是表达式语句 = 表达式 +
;
let y = {
let x = 3;
x + 1 // 整个代码块值为 4 所以 y = 4
}
if 表达式 {
// 表达式必须返回 bool 值,不会隐式转换
...
} else if ... {
...
} else {
...
}
if
是表达式,有返回结果:
let num = if cond {
5 } else {
6 };
loop
:无限循环(可以 break 出来)while
:while 条件 { ... }
for
:for element in array { ... }
break
:退出并从循环返回值
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
}
Range:
for n in (1..4).rev() {
// .rev() 把 Range 反转
...
}
管理权(ownership)主要是管理堆数据
Rust 值的存放:
所有权规则:
栈值克隆:
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
:可克隆
let new = old;
// 之后 old 仍可用
Drop
:要移动
离开作用域时,值被 drop
标量(整浮布字)都 impl 了 Copy;
元组所有元素 Copy,则元组 Copy;
值传给函数:同赋值:
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 的所有权
&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):引用集合中的一段连续的元素。
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
(包括字面量)都可。
定义:
struct User {
email: String
age: u8
}
实例化:
let mut foo = User {
email: String::from("foo@bar.com"),
age: 8,
};
println!("{}", foo.email);
foo.email = String::from("changed@bar.com");
语法糖:变量名与字段同名 => 简写
{foo: foo, } => {foo, }
fn build_user(email: String, age: u8) -> User {
User {
email,
age,
}
}
结构体更新语法
let user2 = User {
email: String::from("user2@bar.com"),
..user1, // 除了显式写的 email 字段,其余用 user1 的值
}
user1
中的 Drop 值被 user2
使用,则等于移动到了 user2
,user1
不再可用;..user1
只用了 user1
中的 Copy 值,则之后 user1
仍然可用:
元组结构体:无字段名,匿名结构体。
struct Color(
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。