解决了什么问题
- 内存安全问题
- 所有权辅助了可以更好的编译优化代码,达到更高的性能
语言基础
-
变量
fn main() { let x = 5; //常量 let mut y = 5; //变量 println!("x: {}", x); y = 6; println!("y: {}", y); let x = 6; //覆盖 }
-
数据类型
let guess: u32 = "42".parse().expect("Not a number!"); //pass let guess = "42".parse().expect("Not a number!"); //complie error 因为类型推断不出来guess是整形
整型
长度 有符号 无符号 8-bit i8
u8
16-bit i16
u16
32-bit i32
u32
64-bit i64
u64
arch isize
usize
数字字面值 例子 Decimal 98_222
Hex 0xff
Octal 0o77
Binary 0b1111_0000
Byte ( u8
only)b'A'
在debug模式,如果整型溢出,会panic,在release模式,不检测溢出
浮点型
默认是f64
fn main() { let x = 2.0; // f64 let y: f32 = 3.0; /f32 }
布尔型
fn main() { let t = true; let f: bool = false; // 显式指定类型注解 }
字符类型
char是 Unicode标量
fn main() { let c = 'z'; let z = 'ℤ'; let heart_eyed_cat = '😻'; }
元组类型
fn main() { let tup: (i32, f64, u8) = (500, 6.4, 1); let tup = (500, 6.4, 1); let (x, y, z) = tup; let z = tup.0; println!("The value of y is: {}", y); }
数组
固定长度
fn main() { let a = [1, 2, 3, 4, 5]; let a: [i32; 5] = [1, 2, 3, 4, 5]; let first = a[0]; }
rust会在运行时检测数组越界并panic
函数
fn main() { let x = plus_one(5); println!("The value of x is: {}", x); } fn plus_one(x: i32) -> i32 { x + 1 //不加;,表示返回值 }
控制流
fn main() { let number = 3; if number < 5 { println!("condition was true"); } else { println!("condition was false"); } let condition = true; let number = if condition { 5 } else { 6 }; }
loop { println!("again!"); } let result = loop { counter += 1; if counter == 10 { break counter * 2; //跳出循环并返回 } }; while number != 0 { println!("{}!", number); number = number - 1; } let a = [10, 20, 30, 40, 50]; for element in a.iter() { println!("the value is: {}", element); }
所有权
作用域
变量离开作用域,则自动释放内存
移动
let s1 = String::from("hello");
le s2 = s1; //类似c++的move
println!("{}, world!", s1); //编译失败
克隆
let s1 = String::from("hello");
let s2 = s1.clone(); //深拷贝
println!("s1 = {}, s2 = {}", s1, s2);
引用
要么 只能有一个可变引用,要么 只能有多个不可变引用 ,为了解决数据竞争问题。rust通过编译来做这些限制
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1);
println!("The length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) -> usize { //常量引用
s.len()
}
fn main() {
let mut s = String::from("hello");
change(&mut s);
}
fn change(some_string: &mut String) { //可变引用
some_string.push_str(", world");
}
悬垂引用
fn dangle() -> &String {
let s = String::from("hello");
&s //编译失败
}
slice
返回string的一段
let s = String::from("hello world");
let hello = &s[0..=4];
let world = &s[6..=10];
fn first_word(s: &String) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
fn main() {
let mut s = String::from("hello world");
let word = first_word(&s);
s.clear(); // 编译失败,内存已经被清空,word不再有效
println!("the first word is: {}", word);
}
结构体
# #[derive(Debug)]
# struct Rectangle {
# width: u32,
# height: u32,
# }
#
impl Rectangle {
fn area(&self) -> u32 { //成员函数
self.width * self.height
}
}
impl Rectangle {
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
fn main() {
let rect1 = Rectangle { width: 30, height: 50 };
let rect2 = Rectangle { width: 10, height: 40 };
let rect3 = Rectangle { width: 60, height: 45 };
println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));
}
枚举
enum IpAddrKind {
V4,
V6,
}
let four = IpAddrKind::V4;
enum IpAddr {
V4(String),
V6(String),
}
let home = IpAddr::V4(String::from("127.0.0.1"));
let loopback = IpAddr::V6(String::from("::1"));
枚举与控制流:
# #[derive(Debug)]
# enum UsState {
# Alabama,
# Alaska,
# }
#
# enum Coin {
# Penny,
# Nickel,
# Dime,
# Quarter(UsState),
# }
#
fn value_in_cents(coin: Coin) -> u32 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("State quarter from {:?}!", state);
25
},
}
}
Option枚举
它用来表示一个变量是Null或者有值
enum Option {
Some(T),
None,
}
let some_number = Some(5);
let some_string = Some("a string");
let absent_number: Option<i32> = None;
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i + 1),
}
}
let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
let some_u8_value = Some(0u8);
if let Some(3) = some_u8_value {
println!("three");
}
集合
vector
变长数组
let v: Vec<i32> = Vec::new();
let v = vec![1, 2, 3];
v.push(5); //追加
v.pop();
let third: &i32 = &v[2];
let does_not_exist = &v[100]; //panic
let does_not_exist = v.get(100); //返回None
let first = &v[0]; //借用
v.push(6); //error, first的内存可能已经被释放
遍历
let v = vec![100, 32, 57];
for i in &v { //常量引用
println!("{}", i);
}
let mut v = vec![100, 32, 57];
for i in &mut v { //可变引用
*i += 50;
}
string
新建:
let mut s = String::new();
let s = "initial contents".to_string();
let s = String::from("initial contents");
追加:
s.push_str("bar");
拼接:
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2; // 注意 s1 被移动了,不能继续使用
string的add函数原型如下:
fn add(self, s: &str) -> String {
s2以常量引用的方式传入add
s1以移动的方式传入add
s1不再拥有所有权
所有权被移交到s3中
let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = format!("{}-{}-{}", s1, s2, s3);
通过format,s1 s2 s3的所有权都得以保留
索引
let s1 = String::from("hello");
let h = s1[0]; //error
字符串不能索引,因为String支持的编码类型复杂
遍历
for c in "नमस्ते".chars() {
println!("{}", c);
}
for b in "नमस्ते".bytes() {
println!("{}", b);
}
哈希map
新建
use std::collections::HashMap;
let mut map = HashMap::new();
插入
let field_name = String::from("Favorite color");
let field_value = String::from("Blue");
map.insert(field_name, field_value);
// 这里 field_name 和 field_value 不再有效
map.insert(String::from("Hate"), String::from("Red"));
map.entry(String::from("OK")).or_insert(String::from("Yello")); //只有键不存在时插入,返回value的指针
println!("{:?}", map);
访问
let name = String::from("OK");
let color = map.get(&name);
for (key, value) in &map { //常量引用s
println!("{}: {}", key, value);
}
错误
panic
不可恢复异常,程序会输出bt
fn main() {
panic!("crash and burn");
}
fn main() {
let v = vec![1, 2, 3];
v[99]; //越界,panic
}
result
可恢复错误
use std::io;
use std::io::Read;
use std::fs::File;
fn read_username_from_file() -> Result<String, io::Error> {
let f = File::open("hello.txt");
let mut f = match f {
Ok(file) => file,
Err(e) => return Err(e),
};
let mut s = String::new();
match f.read_to_string(&mut s) {
Ok(_) => Ok(s),
Err(e) => Err(e),
}
}
泛型
struct Point<T> {
x: T,
y: T,
}
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}
fn main() {
let p = Point { x: 5, y: 10 };
println!("p.x = {}", p.x());
}
impl Point<f32> { //对f32单态化后,实现函数
fn distance_from_origin(&self) -> f32 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}
trait
接口
pub trait Summary {
fn summarize(&self) -> String;
}
pub struct NewsArticle {
pub headline: String,
pub location: String,
pub author: String,
pub content: String,
}
impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}, by {} ({})", self.headline, self.author, self.location)
}
}
pub struct Tweet {
pub username: String,
pub content: String,
pub reply: bool,
pub retweet: bool,
}
impl Summary for Tweet {
fn summarize(&self) -> String { //多态
format!("{}: {}", self.username, self.content)
}
}
let tweet = Tweet { //实例化
username: String::from("horse_ebooks"),
content: String::from("of course, as you probably already know, people"),
reply: false,
retweet: false,
};
println!("1 new tweet: {}", tweet.summarize());
接口作为参数
pub fn notify(item: impl Summary) {
println!("Breaking news! {}", item.summarize());
}
fn some_function<T, U>(t: T, u: U) -> i32
where T: Display + Clone,
U: Clone + Debug
{
}
fn returns_summarizable(switch: bool) -> impl Summary {
if switch {
NewsArticle {
headline: String::from("Penguins win the Stanley Cup Championship!"),
location: String::from("Pittsburgh, PA, USA"),
author: String::from("Iceburgh"),
content: String::from("The Pittsburgh Penguins once again are the best
hockey team in the NHL."),
}
} else {
Tweet {
username: String::from("horse_ebooks"),
content: String::from("of course, as you probably already know, people"),
reply: false,
retweet: false,
}
}
}
泛型与trait
Copy代表类型T可以被拷贝
PartialOrd代表T为数字类型
Display 代表T可以被打印
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
let mut largest = list[0];
for &item in list.iter() {
if item > largest {
largest = item;
}
}
largest
}
fn main() {
let number_list = vec![34, 50, 25, 100, 65];
let result = largest(&number_list);
println!("The largest number is {}", result);
let char_list = vec!['y', 'm', 'a', 'q'];
let result = largest(&char_list);
println!("The largest char is {}", result);
}
生命周期省略
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
- 每一个引用参数都有它的生命周期参数
- 如果只有一个输入生命周期参数,那么它被赋予所有输出生命周期参数
- 如果有多个输入生命周期参数,且其中一个参数被标记&self,那么self的生命周期被赋予所有输出生命周期
智能指针
以引用计数来管理内存
在堆创建数据
fn main() {
let b = Box::new(5);
println!("b = {}", b);
}
创建递归类型
enum List {
Cons(i32, Box<List>),
Nil,
}
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1,
Box::new(Cons(2,
Box::new(Cons(3,
Box::new(Nil))))));
}
提早释放
fn main() {
let c = CustomSmartPointer { data: String::from("some data") };
println!("CustomSmartPointer created.");
drop(c);
println!("CustomSmartPointer dropped before the end of main.");
}
增加引用
enum List {
Cons(i32, Box<List>),
Nil,
}
use crate::List::{Cons, Nil};
fn main() {
let a = Cons(5,
Box::new(Cons(10,
Box::new(Nil))));
let b = Cons(3, Box::new(a)); //move
let c = Cons(4, Box::new(a)); //error
}
正确的做法:
enum List {
Cons(i32, Rc<List>),
Nil,
}
use crate::List::{Cons, Nil};
use std::rc::Rc;
fn main() {
let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
let b = Cons(3, Rc::clone(&a)); //增加计数,只读引用,数据不可变
let c = Cons(4, Rc::clone(&a)); //增加计数,只读引用,数据不可变
}
可变引用,计数增加:
enum List {
Cons(Rc<RefCell<i32>>, Rc<List>),
Nil,
}
use crate::List::{Cons, Nil};
use std::rc::Rc;
use std::cell::RefCell;
fn main() {
let value = Rc::new(RefCell::new(5));
let a = Rc::new(Cons(Rc::clone(&value), Rc::new(Nil)));
let b = Cons(Rc::new(RefCell::new(6)), Rc::clone(&a));
let c = Cons(Rc::new(RefCell::new(10)), Rc::clone(&a));
*value.borrow_mut() += 10;
println!("a after = {:?}", a);
println!("b after = {:?}", b);
println!("c after = {:?}", c);
}
解决循环引用
使用weak代替Rc
并行编程
多线程
use std::thread;
use std::time::Duration;
fn main() {
let handle = thread::spawn(|| {
for i in 1..10 {
println!("hi number {} from the spawned thread!", i);
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("hi number {} from the main thread!", i);
thread::sleep(Duration::from_millis(1));
}
handle.join().unwrap();
}
线程使用主线程变量
use std::thread;
fn main() {
let v = vec![1, 2, 3];
let handle = thread::spawn(move || {
println!("Here's a vector: {:?}", v);
});
handle.join().unwrap();
}
消息传递
# use std::thread;
# use std::sync::mpsc;
# use std::time::Duration;
#
# fn main() {
// --snip--
let (tx, rx) = mpsc::channel();
let tx1 = mpsc::Sender::clone(&tx); //多生产者
thread::spawn(move || {
let vals = vec![
String::from("hi"),
String::from("from"),
String::from("the"),
String::from("thread"),
];
for val in vals {
tx1.send(val).unwrap();
thread::sleep(Duration::from_secs(1));
}
});
thread::spawn(move || {
let vals = vec![
String::from("more"),
String::from("messages"),
String::from("for"),
String::from("you"),
];
for val in vals {
tx.send(val).unwrap(); //val所有权转移
thread::sleep(Duration::from_secs(1));
}
});
for received in rx {
println!("Got: {}", received);
}
// --snip--
# }
多线程共享可变变量
use std::sync::{Mutex, Arc};
use std::thread;
fn main() {
let counter = Arc::new(Mutex::new(0)); //Arc是带有原子性的智能指针,Rc是不带原子性的智能指针
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
}