Rust ๆๆ ธๅฟ็ๆฆๅฟตโโๆๆๆใๅ็จใ็ๅฝๅจๆใ่ฟๆฏ Rust ๅๅ ถไป่ฏญ่จๆๆฌ่ดจ็ๅบๅซ๏ผไนๆฏ็ผ่ฏๅจ่ฝไฟ่ฏๅ ๅญๅฎๅ จ็ๆ นๅบใ็่งฃๅฎ๏ผไฝ ๅฐฑ็่งฃไบ Rust ็ไธๅ่ฎพ่ฎก้ๆฉใ
ๅ ๅญ็ฎก็ๆฏ็ณป็ป็ผ็จ็ๆ ธๅฟ้พ้ขใๅจ Rust ไนๅ๏ผไธ็ไธป่ฆ้็จไธค็งๆนๆก๏ผไฝ้ฝๆๆๆพ็้ฎ้ขใ
// ็ปๅ
ธ็ use-after-free
int* p = (int*)malloc(sizeof(int));
*p = 42;
free(p);
// ... ๅ ็พ่กไนๅ ...
int x = *p; // ๐ฅ ๆชๅฎไน่กไธบ๏ผๅฏ่ฝๅดฉ๏ผๅฏ่ฝไธๅดฉ๏ผๆๆๆ็ๆฏ"ๅฅฝๅ่ฝ่ท"
C++ ็จๅบๅ่ฑๅคง้ๆถ้ด่ฐ่ฏๅ ๅญ้ฎ้ขใValgrindใAddressSanitizerใๆบ่ฝๆ้โโ่ฟไบ้ฝๆฏๅฏนๆๅจ็ฎก็็ผบ้ท็่กฅๆๆชๆฝ๏ผ่้ๆ นๆฌ่งฃๅณๆนๆกใ
func process() *Data {
d := &Data{...}
// Go ็ GC ไผๅจๆไธชไธ็กฎๅฎ็ๆถๅปๅๆถ
// ไฝ GC ้่ฆ่ฟ่กๆถ๏ผๅ ็จ้ขๅค 5-20% CPU
// ไธ STW(Stop-The-World) ๅฏผ่ดๅปถ่ฟๆๅจ
return d
}
Go ็ GC ่ฝ็ถไฝๅปถ่ฟ๏ผไฝไป็ถ๏ผ
Rust ็ๆดๅฏๆฏ๏ผๅ ๅญๅฎๅ จ็่งๅๅฏไปฅๅจ็ผ่ฏๆ้ๆๆฃๆฅ๏ผ่ไธ้่ฆ่ฟ่กๆถ GCใไปฃไปทๆฏ็จๅบๅๅฟ ้กปๅจไปฃ็ ไธญๆพๅผ่กจ่พพ"่ฐๆฅๆ่ฟๅๅ ๅญ"โโไฝ่ฟๆฐๆฐไฝฟๅพ็จๅบๅ็ๆๅพๆดๆธ ๆฐใ
๐ก ๆ ธๅฟๆๆณ๏ผๆๆๆไธๆฏ้ๅถ๏ผๆฏๅฅ็บฆใไฝ ๅ่ฏ็ผ่ฏๅจ"่ฟๅๅ ๅญๅฝ่ฐ็ฎก"๏ผ็ผ่ฏๅจๅธฎไฝ ไฟ่ฏไธไผๅบ้ฎ้ขใๅฆๆๅฅ็บฆไธๅ็๏ผ็ผ่ฏๅจๅจ็ผ่ฏๆๅฐฑๆ็ปไฝ ๏ผ่ไธๆฏๅจ่ฟ่กๆถๅดฉๆบใ
Rust ็ๆๆๆ็ณป็ปๅปบ็ซๅจไธๆก็ฎๅ่งๅไนไธ๏ผ
let s = String::from("hello");
// s ๆฏ "hello" ่ฟไธช String ๅผ็ owner
// ๅชๆไธไธช owner๏ผๅฐฑๆฏ s
let x: i32 = 42;
let y = x; // i32 ๅฎ็ฐไบ Copy
// x ๅ y ้ฝๆๆ๏ผๅผ่ขซๅคๅถ
let s1 = String::from("hello");
let s2 = s1; // String ๆฒกๆๅฎ็ฐ Copy
// s1 ่ขซ็งปๅจๅฐ s2๏ผs1 ไธๅๆๆ
println!("{}", s1); // โ value borrowed
// here after move
fn main() {
{
let s = String::from("hello");
// s ๅจ่ฟไธชไฝ็จๅๅ
ๆๆ
} // โ s ็ฆปๅผไฝ็จๅ๏ผ่ชๅจ่ฐ็จ drop(s)
// ๅ ไธ็ "hello" ่ขซ้ๆพ๏ผๆ ้ๆๅจ free
// println!("{}", s); // โ s ไธๅญๅจไบ
}
| ็นๆง | C++ RAII | Rust ๆๆๆ |
|---|---|---|
| ่ชๅจๆๆ | ๆๆๅฝๆฐ | Drop trait |
| ๆท่ด่ฏญไน | ้ป่ฎคๆทฑๆท่ด | ้ป่ฎค move |
| ๆฌๅๅผ็จ | ๅฏ่ฝๅ็ | ็ผ่ฏๆ้ปๆญข |
| ๅ้้ๆพ | ๅฏ่ฝๅ็ | ไธๅฏ่ฝ(move ๅๅๅ้ๆ ๆ) |
| ๆบ่ฝๆ้ | unique_ptr/shared_ptr | Box/Arc/Rc |
Move ่ฏญไนๆฏๆๆๆ็ณป็ป็ๆ ธๅฟๆบๅถใ็่งฃ move๏ผๅฐฑ็่งฃไบ Rust ไธบไปไนไธ้่ฆ GCใ
String ็ฑๆ ไธ็ๅ ๆฐๆฎ๏ผๆ้ใ้ฟๅบฆใๅฎน้๏ผๅๅ ไธ็ๅฎ้ ๆฐๆฎ็ปๆใ่ตๅผๆถ๏ผๆ ไธ็ๅ ๆฐๆฎ่ขซๅคๅถ๏ผไฝๅ ๆฐๆฎไธไผโโๅฆๅไธคไธช owner ้ฝไผๅฐ่ฏ้ๆพๅไธๅๅ ๅญใ
๐ซ ็ผ่ฏๅจ่ฏดไธ่ก๏ผlet s2 = s1; ไนๅไฝฟ็จ s1 ไผๅพๅฐ error[E0382]: use of moved value: s1ใ่ฟไธๆฏๅปบ่ฎฎ๏ผๆฏ็กฌๆง็ผ่ฏ้่ฏฏใ
ๅฆๆ็ฑปๅ็ๅ
จ้จๆฐๆฎ้ฝๅจๆ ไธ๏ผไธๅคๅถๆๆฌไฝ๏ผRust ๅ
่ฎธๅฎๅฎ็ฐ Copy traitใCopy ็ฑปๅ่ตๅผๆถ่ชๅจๅคๅถ๏ผๅๅ้ไป็ถๆๆใ
let x: i32 = 42;
let y = x; // i32 ๆฏ Copy ็ฑปๅ๏ผๅผ่ขซๅคๅถ
println!("x = {}, y = {}", x, y); // โ
ไธคไธช้ฝๆๆ
let a = (1, 2.0, true); // ๅ
็ปๅ
้ฝๆฏ Copy ็ฑปๅ
let b = a; // ๆดไธชๅ
็ปไนๆฏ Copy
println!("{:?}", a); // โ
ไป็ถๆๆ
| Copy ็ฑปๅ โ | ้ Copy ็ฑปๅ โ |
|---|---|
| ๆๆๆดๆฐ็ฑปๅ (i8..i128, u8..u128) | String |
| ๆตฎ็นๆฐ (f32, f64) | Vec<T> |
| ๅธๅฐๅผ (bool) | Box<T> |
| ๅญ็ฌฆ (char) | HashMap / BTreeMap |
| ๅ ็ป๏ผไป ๅซ Copy ็ฑปๅ๏ผ | ๅ ็ป๏ผๅซ้ Copy ็ฑปๅ๏ผ |
| ๆฐ็ป [T; N]๏ผT: Copy๏ผ | ๆฐ็ป๏ผT ้ Copy๏ผ |
| ๅ ฑไบซๅผ็จ &T | ๅฏๅๅผ็จ &mut T |
โ ๏ธ ๆณจๆ๏ผ&mut T ไธๆฏ Copy๏ผๅไธๆถๅปๅช่ฝๆไธไธชๅฏๅๅผ็จ๏ผๅฆๆ Copy ๅฐฑ่ฟๅไบๅ็จ่งๅใ&T ๆฏ Copy๏ผๅ ไธบๅคไธชไธๅฏๅๅผ็จๆฏๅ
่ฎธ็ใ
let s1 = String::from("hello");
let s2 = s1.clone(); // ๆพๅผๆทฑๆท่ด๏ผๅ ๆฐๆฎไน่ขซๅคๅถ
println!("s1 = {}, s2 = {}", s1, s2); // โ
ไธคไธช้ฝๆๆ
ๆๅผไผ ็ปๅฝๆฐ๏ผๅ่ตๅผไธๆ ทโโ่ฆไน move๏ผ่ฆไน copyใ
fn print_i32(x: i32) {
println!("{}", x);
}
let n = 42;
print_i32(n);
println!("{}", n); // โ
n ไป็ถๆๆ
fn print_string(s: String) {
println!("{}", s);
} // s ่ขซ drop
let s = String::from("hello");
print_string(s);
println!("{}", s); // โ s ๅทฒ่ขซ move
// error: value borrowed after move
่งฃๅณๅๆณ๏ผไผ ๅผ็จ๏ผไธไธ่่ฏฆ่ฟฐ๏ผ๏ผๆ่ ไผ ๆๆๆๅ่ฟๅใ
// ๆนๆก1๏ผไผ ๅผ็จ
fn print_string(s: &String) {
println!("{}", s);
}
let s = String::from("hello");
print_string(&s);
println!("{}", s); // โ
s ไป็ถๆๆ
// ๆนๆก2๏ผ่ฟๅๆๆๆ
fn consume_and_return(s: String) -> String {
println!("{}", s);
s // ๆๆๆ่ฟๅ็ป่ฐ็จ่
}
let s = String::from("hello");
let s = consume_and_return(s); // ้ๆฐ็ปๅฎ
println!("{}", s); // โ
ๅฆๆๆฏๆฌกไผ ๅ้ฝ่ฆ move ๅ่ฟๅ๏ผไปฃ็ ไผ้ๅธธๅฐๅฆใRust ็่งฃๅณๆนๆกๆฏๅ็จโโๅๅปบไธไธชๆๅๅผ็ๅผ็จ๏ผไฝไธ่ทๅๆๆๆใ
fn calculate_length(s: &String) -> usize {
s.len()
} // s ็ฆปๅผไฝ็จๅ๏ผไฝๅ ไธบๅฎๆฒกๆๆๆๆ๏ผไธไผ drop ๅๅผ
let s1 = String::from("hello");
let len = calculate_length(&s1);
// s1 ไป็ถๆๆ๏ผๆไปฌๅชๆฏ"ๅ"็ปๅฝๆฐ็ไบ็
println!("'{}' ็้ฟๅบฆๆฏ {}", s1, len);
fn add_world(s: &mut String) {
s.push_str(", world");
}
let mut s = String::from("hello");
add_world(&mut s);
println!("{}", s); // "hello, world"
let s = String::from("hello");
let r1 = &s; // ็ฌฌ1ไธช &T
let r2 = &s; // ็ฌฌ2ไธช &T
let r3 = &s; // ็ฌฌ3ไธช &T
println!("{} {} {}", r1, r2, r3);
// โ
ๅคไธช่ฏปๆฒก้ฎ้ข
let mut s = String::from("hello");
let r1 = &s; // ไธๅฏๅๅผ็จ
let r2 = &mut s; // โ ๅฏๅๅผ็จ
println!("{} {}", r1, r2);
// error: cannot borrow `s` as mutable
// because it is also borrowed as immutable
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s; // โ
// error: cannot borrow `s` as mutable
// more than once at a time
let mut s = String::from("hello");
{
let r1 = &mut s;
r1.push_str("1");
} // r1 ็ๅฝๅจๆ็ปๆ
let r2 = &mut s; // โ
r1 ๅทฒๅคฑๆ
r2.push_str("2");
Rust 2018 ๅผๅ ฅไบ NLL๏ผๅผ็จ็็ๅฝๅจๆๅจๆๅไธๆฌกไฝฟ็จๆถ็ปๆ๏ผ่ไธๆฏๅจไฝ็จๅ็ปๆๆถใ่ฟ่ฎฉไปฃ็ ๆด่ช็ถ๏ผ
let mut s = String::from("hello");
let r1 = &s;
println!("{}", r1); // r1 ๆๅไธๆฌกไฝฟ็จ
// r1 ็็ๅฝๅจๆๅจๆญค็ปๆ๏ผNLL๏ผ๏ผๅณไฝฟไฝ็จๅๆช็ปๆ
let r2 = &mut s; // โ
ๅจ NLL ไธๅฏไปฅ็ผ่ฏ
println!("{}", r2);
๐ก NLL ็ๆไน๏ผๅผ็จ็็ๅฝๅจๆไธๆฏ็่ฑๆฌๅท๏ผ่ๆฏ็ๅฎ้ ไฝฟ็จไฝ็ฝฎใ็ผ่ฏๅจไผๅๆๅผ็จ็"ๆดป่ท่ๅด"๏ผๅชๅจ็ๆญฃๅฒ็ชๆถๆฅ้ใ่ฟ่ฎฉๅคง้ไนๅๆ ๆณ็ผ่ฏ็ไปฃ็ ๅๅพๅๆณใ
| ็นๆง | Go | Rust |
|---|---|---|
| ๅ ฑไบซๅฏๅ็ถๆ | ๅ ่ฎธ๏ผ้ๅ ้ไฟ่ฏๅฎๅ จ๏ผ | ็ผ่ฏๆ็ฆๆญข |
| ๆฐๆฎ็ซไบ | ่ฟ่กๆถๆฃๆต (race detector) | ็ผ่ฏๆๆถ้ค |
| ๆ้ๅฎๅ จ | GC ไฟ่ฏไธๆฌๅ | ๅ็จ่งๅไฟ่ฏไธๆฌๅ |
| ๅนถๅๅฎๅ จ | Channel / Mutex | Send + Sync + ๅ็จ่งๅ |
ๆฌๅๅผ็จ๏ผDangling Reference๏ผๆฏๆๅผ็จๆๅไบๅทฒ่ขซ้ๆพ็ๅ ๅญใๅจ C/C++ ไธญ่ฟๆฏๆๅธธ่ง็ๅฎๅ จๆผๆดๆฅๆบไนไธใRust ็ๅ็จ่งๅๅจ็ผ่ฏๆๅฐฑๆ็ปไบๅฎใ
fn produce_string() -> String {
let s = String::from("hello");
s // ๆๆๆ่ฝฌ็งปๅฐ่ฐ็จ่
}
let s = produce_string();
println!("{}", s); // โ
fn dangling() -> &String {
let s = String::from("hello");
&s // โ ่ฟๅๅฑ้จๅ้็ๅผ็จ
} // s ่ขซ drop๏ผๅผ็จๆฌๅ
// error: missing lifetime specifier
// this function's return type contains
// a borrowed value, but there is no value
// for it to be borrowed from
// C++ ไธญ่ฟๆฎตไปฃ็ ่ฝ็ผ่ฏ๏ผไฝ่ฟ่กๆถๆชๅฎไน่กไธบ
std::string& dangling() {
std::string s = "hello";
return s; // ่ฟๅๅฑ้จๅ้็ๅผ็จ
} // s ่ขซ้ๆฏ๏ผๅผ็จๆฌๅ
// ่ฐ็จ่
ๅพๅฐไธไธชๆฌๅๅผ็จโโๅฏ่ฝ"ๆญฃๅธธๅทฅไฝ"๏ผไนๅฏ่ฝๅดฉๆบ
๐ซ ็ผ่ฏๅจ่ฏดไธ่ก๏ผRust ็ผ่ฏๅจ็ๅฐ -> &String ไฝๅฝๆฐไฝๅ
ๆฒกๆๅฏไปฅไปๅๆฐๅ็จ็ๅผ๏ผ็ดๆฅๆฅ้ missing lifetime specifierใไฝ ๅฟ
้กป่ฆไน่ฟๅๆฅๆๆๆๆ็ String๏ผ่ฆไนไปๅๆฐไธญๅ็จโโ็ผ่ฏๅจไผ้ช่ฏๅ็จ็ๅๆณๆงใ
ๅฝๅฝๆฐๆฅๅๅผ็จๅๆฐๅนถ่ฟๅๅผ็จๆถ๏ผ็ผ่ฏๅจ้่ฆ็ฅ้่ฟๅ็ๅผ็จๅๅชไธช่พๅ ฅๅผ็จๅ ณ่ใ็ๅฝๅจๆๆ ๆณจๅฐฑๆฏๅ่ฏ็ผ่ฏๅจ่ฟไธชๅ ณ่ๅ ณ็ณปใ
fn longest(x: &str, y: &str) -> &str {
if x.len() > y.len() { x } else { y }
}
// โ ็ผ่ฏๅจไธ็ฅ้่ฟๅๅผๅผ็จ็ๆฏ x ่ฟๆฏ y
// ๅฆๆ x/y ็ๅฎ้
็ๅฝๅจๆไธๅ๏ผๅฏ่ฝไบง็ๆฌๅๅผ็จ
็ๅฝๅจๆๅๆฐ็จ 'aใ'b ็ญ่กจ็คบ๏ผๅๅจ & ๅ้ขใๅฎไปฌไธๆนๅไปปไฝๅผ็จ็ๅฎ้
็ๅฝๅจๆ๏ผๅชๆฏๆ่ฟฐๅผ็จไน้ด็ๅ
ณ็ณปใ
// ๅ่ฏ็ผ่ฏๅจ๏ผ่ฟๅๅผ็็ๅฝๅจๆ่ณๅฐๅ xใy ไธญ่พ็ญ็ไธๆ ท้ฟ
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
fn main() {
let s1 = String::from("long string"); // โโโ s1 ็ๅฝๅจๆๅผๅง
let result;
{
let s2 = String::from("xyz"); // โโโ s2 ็ๅฝๅจๆๅผๅง
result = longest(s1.as_str(), s2.as_str());
println!("{}", result); // โ
s1 ๅ s2 ้ฝ่ฟๆดป็
} // โโโ s2 ็ๅฝๅจๆ็ปๆ
// println!("{}", result); // โ s2 ๅทฒๆญป๏ผresult ๅฏ่ฝๅผ็จ s2
}
็ปๆไฝๅฆๆๆๆๅผ็จ๏ผๅฟ ้กปๆ ๆณจ็ๅฝๅจๆโโๅ่ฏ็ผ่ฏๅจ่ฟไธชๅผ็จ่ณๅฐๆดปๅคไน ใ
struct Parser<'a> {
input: &'a str,
pos: usize,
}
impl<'a> Parser<'a> {
fn new(input: &'a str) -> Self {
Parser { input, pos: 0 }
}
fn peek(&self) -> Option<char> {
self.input[self.pos..]
.chars().next()
}
}
struct Parser {
input: &str,
pos: usize,
}
// error: missing lifetime specifier
// this struct has a reference field
// which must have a lifetime
๐ก ็ป้ชๆณๅ๏ผๅฆๆไฝ ๅ็ฐ้่ฆๅจ็ปๆไฝไธญๆๆๅผ็จ๏ผๅ
่่ๆฏๅฆๅฏไปฅ็จๆฅๆๆๆๆ็็ฑปๅๆฟไปฃ๏ผๅฆ String ไปฃๆฟ &str๏ผVec<T> ไปฃๆฟ &[T]๏ผใๆๆๅผ็จๆๅณ็็ปๆไฝ็็ๅฝๅจๆๅ้ไบๅผ็จ็ฎๆ ๏ผ่ฟไผๅคงๅน
้ๅถ็ตๆดปๆงใๅชๅจๆง่ฝๅ
ณ้ฎ่ทฏๅพๆ้ถๆท่ดๅบๆฏไธญไฝฟ็จๅผ็จๅญๆฎตใ
็ผ่ฏๅจๅจ็ฎๅๅบๆฏไธๅฏไปฅ่ชๅจๆจๆญ็ๅฝๅจๆ๏ผไธ้่ฆๆๅจๆ ๆณจใไธๆก็็ฅ่งๅ๏ผ
// ็็ฅๅๆณ๏ผ็ผ่ฏๅจ่ชๅจๆจๆญ๏ผ
fn first_word(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
// ็ญไปท็ๅฎๆดๆ ๆณจ
fn first_word<'a>(s: &'a str) -> &'a str {
// ...
}
'static ๆฏไธไธช็นๆฎ็็ๅฝๅจๆ๏ผ่กจ็คบๅผ็จๅจๆดไธช็จๅบ่ฟ่กๆ้ด้ฝๆๆใ
let s: &'static str = "hello world";
// ๅญ็ฌฆไธฒๅญ้ข้็ดๆฅ็ผ่ฏ่ฟไบ่ฟๅถๆไปถ๏ผๆฐธไธ่ฟๆ
โ ๏ธ ๅธธ่ง่ฏฏ่งฃ๏ผT: 'static ่กจ็คบ T ไธญไธๅซไปปไฝ็ญไบ 'static ็ๅผ็จ๏ผ่้ T ๆฌ่บซๅฟ
้กปๆดปๅฐ็จๅบ็ปๆใๆๆๆฅๆๆๆๆ็็ฑปๅ๏ผๅฆ StringใVec<T>๏ผ้ฝๆปก่ถณ T: 'static๏ผๅ ไธบๅฎไปฌไธไพ่ตๅค้จๅผ็จใ
// String ๆปก่ถณ 'static ็บฆๆ๏ผๆฅๆๆๆๆ๏ผๆ ็ญ็ๅฝๅจๆๅผ็จ๏ผ
fn takes_static<T: 'static>(t: T) {}
takes_static(String::from("hello")); // โ
String: 'static
takes_static(42); // โ
i32: 'static
takes_static("literal"); // โ
&'static str: 'static
// ไฝ่ฟไธชไธ่ก๏ผ
fn bad() {
let s = String::from("hello");
let r = &s;
takes_static(r); // โ &s ไธๆฏ 'static
}
std::thread::spawn ่ฆๆฑ้ญๅ
F: FnOnce() + Send + 'staticconst ๅ static ๅผๅฟ
้กปๆฏ 'staticimpl Error + 'static ็กฎไฟ std::any::Any downcast ๅฏ็จๅฝ็ปๆไฝๆๆๆฅ่ชไธๅๆฅๆบ็ๅผ็จๆถ๏ผ้่ฆไธๅ็็ๅฝๅจๆๅๆฐ๏ผ
struct Context<'input, 'config> {
input: &'input str, // ่พๅ
ฅๆฐๆฎ
config: &'config Config, // ้
็ฝฎไฟกๆฏ
}
impl<'input, 'config> Context<'input, 'config> {
fn process(&self) -> &'input str {
// ่ฟๅๅผๅชๅ
ณ่ input๏ผไธๅ config ็ๅฝๅจๆ้ๅถ
self.input
}
}
// T: 'a ่กจ็คบ T ไธญ็ๆๆๅผ็จ่ณๅฐๆดป 'a
struct RefWrapper<'a, T: 'a> {
reference: &'a T,
}
// 'a: 'b ่กจ็คบ็ๅฝๅจๆ 'a ่ณๅฐๅ 'b ไธๆ ท้ฟ
fn choose_first<'a, 'b: 'a>(first: &'a str, _second: &'b str) -> &'a str {
first
}
// where ๅญๅฅไธญๅ็บฆๆ๏ผๆดๆธ
ๆฐ
fn complex<'a, 'b>(
x: &'a str,
y: &'b str,
) -> &'a str
where
'b: 'a, // 'b ่ณๅฐๅ 'a ไธๆ ท้ฟ
{
x
}
ๅฏนไบ้ญๅ ๅ trait ไธญ็็ๅฝๅจๆ๏ผๆๆถ้่ฆ"ๅฏนๆๆ็ๅฝๅจๆ้ฝๆ็ซ"็็บฆๆ๏ผ
// for<'a> ่กจ็คบ"ๅฏนๆๆ็ๅฝๅจๆ 'a"
// ๅธธ่งไบ Fn trait bounds
fn call_with_ref<F>(f: F)
where
F: for<'a> Fn(&'a i32) -> &'a i32,
{
let x = 42;
let result = f(&x);
println!("{}", result);
}
// ่ฟไธช้ญๅ
ๆปก่ถณ for<'a> Fn(&'a i32) -> &'a i32
// ๅ ไธบๅฎๅฏนไปปๆ่พๅ
ฅๅผ็จ็็ๅฝๅจๆ้ฝๆ็ซ
call_with_ref(|x| x);
โ ๏ธ HRTB ไธๅธธ็จ๏ผๆฅๅธธ็ผ็ ไธญๅพๅฐ้่ฆๆๅ for<'a>ใๅฎไธป่ฆๅบ็ฐๅจๅบ็ API ่ฎพ่ฎกไธญ๏ผ็นๅซๆฏๆถๅ้ญๅ
ๅๅ่ฐ็ๅบๆฏใๅฆๆไฝ ้ๅฐไบ๏ผๅคงๆฆ็ๅฏไปฅ็จๆด็ฎๅ็ๆนๅผ้ๅใ
let mut v = vec![1, 2, 3, 4, 5];
let first = &v[0]; // ไธๅฏๅๅผ็จ
v.push(6); // โ ๅฏๅๅ็จ
// push ๅฏ่ฝๅฏผ่ด้ๆฐๅ้
// first ๅฏ่ฝๆฌๅ๏ผ
println!("{}", first);
let mut v = vec![1, 2, 3, 4, 5];
let first = v[0]; // Copy ๅบๆฅ
v.push(6); // โ
ๆฒกๆๅผ็จๅฒ็ช
println!("{}", first);
// โ ๆ ๆณ็ดๆฅ่กจ่พพ่ชๅผ็จ
struct SelfRef {
data: String,
pointer: &str, // ๆณๆๅ data๏ผไฝ็ๅฝๅจๆๆไนๅ๏ผ
}
// ๅฐ่ฏ1๏ผ็ๅฝๅจๆๆ ๆณจ
struct SelfRef2<'a> {
data: String,
pointer: &'a str, // 'a ไปๅชๆฅ๏ผ
}
// ๆ ๆณๅๅปบ๏ผๅ ไธบ data ็ๅฐๅๅจๆ้ ๅๆ็ฅ้๏ผ
// ่ 'a ้่ฆๅจๆ้ ๆถ็กฎๅฎ
่ชๅผ็จ็ปๆๅจ Rust ไธญๆฏไธช็ปๅ ธ้พ้ขใ่งฃๅณๆนๆก๏ผ
| ๆนๆก | ๅ็ | ้็จๅบๆฏ |
|---|---|---|
| Pin<Box<T>> | ไฟ่ฏๆฐๆฎไธไผ่ขซ move | async/await ็ๆ็ Future |
| ็ดขๅผๆฟไปฃๅผ็จ | ็จ usize ็ดขๅผไปฃๆฟๆ้ | slotmap / arena |
| owning_ref crate | ๅฐ่ฃ ๅฎๅ จ็่ชๅผ็จ | ้่ฆ่ชๅผ็จ็ๅฎนๅจ |
| rental crate | ๅฃฐๆๅผ่ชๅผ็จ | ๅคๆ่ชๅผ็จๅบๆฏ๏ผๅทฒๅผ็จ๏ผ |
| ้ๆฐ่ฎพ่ฎก | ้ฟๅ ่ชๅผ็จ | ๅคงๅคๆฐๆ ๅตไธๆไฝณ |
// ็จ็ดขๅผไปฃๆฟๅผ็จ๏ผ็ป่ฟ็ๅฝๅจๆ้ฎ้ข
struct SelfRefIndexed {
data: Vec<String>,
pointer_idx: usize, // ๆๅ data[pointer_idx]
}
impl SelfRefIndexed {
fn get_ref(&self) -> &str {
&self.data[self.pointer_idx]
}
}
Rust ็ๆๆๆๆจกๅๅคฉ็ถ้ฒๆญขไบๅพช็ฏๅผ็จๅฏผ่ด็ๅ
ๅญๆณๆผโโไฝๅฆๆไฝ ็จ Rc/Arc๏ผๅพช็ฏๅผ็จไป็ถๅฏ่ฝๅ็๏ผ
use std::rc::{Rc, Weak};
use std::cell::RefCell;
struct Node {
value: i32,
parent: RefCell<Weak<Node>>, // Weak ๅผ็จ๏ผไธๅขๅ ๅผ็จ่ฎกๆฐ
children: RefCell<Vec<Rc<Node>>>, // Strong ๅผ็จ
}
let leaf = Rc::new(Node {
value: 3,
parent: RefCell::new(Weak::new()),
children: RefCell::new(vec![]),
});
let branch = Rc::new(Node {
value: 5,
parent: RefCell::new(Weak::new()),
children: RefCell::new(vec![Rc::clone(&leaf)]),
});
*leaf.parent.borrow_mut() = Rc::downgrade(&branch);
// branch โ leaf (Strong)
// leaf โ branch (Weak) โ ไธ้ปๆญข branch ่ขซ้ๆพ
struct User {
name: String,
email: String,
active: bool,
}
let user1 = User {
name: String::from("Alice"),
email: String::from("alice@example.com"),
active: true,
};
// ็ปๆไฝๆดๆฐ่ฏญๆณไผ move ๅญๆฎต๏ผ
let user2 = User {
name: String::from("Bob"),
..user1 // email ๅ active ไป user1 move ่ฟๆฅ
};
// println!("{}", user1.email); // โ email ๅทฒ่ขซ move
println!("{}", user1.name); // โ
name ๆฒก่ขซ move๏ผuser2 ๆพๅผๆไพไบ๏ผ
println!("{}", user1.active); // โ
bool ๆฏ Copy ็ฑปๅ
้่ฟไป้ถๅฎ็ฐไธไธช็ฎๅ็ MyString๏ผๆทฑๅ
ฅ็่งฃๆๆๆใmoveใdrop ็ๅบๅฑๆบๅถใ
use std::alloc::{alloc, dealloc, realloc, Layout};
use std::ptr::{self, copy_nonoverlapping};
use std::ops::{Deref, DerefMut};
use std::fmt;
pub struct MyString {
ptr: *mut u8, // ๆๅๅ ไธๆฐๆฎ็ๆ้
len: usize, // ๅฝๅ้ฟๅบฆ
cap: usize, // ๅฎน้
}
impl MyString {
/// ไป &str ๅๅปบ MyString
pub fn from_str(s: &str) -> Self {
let len = s.len();
let cap = len.max(1); // ่ณๅฐๅ้
1 ๅญ่
let layout = Layout::array::<u8>(cap).unwrap();
let ptr = unsafe { alloc(layout) };
if ptr.is_null() {
panic!("allocation failed");
}
// ๅคๅถๆฐๆฎๅฐๅ
unsafe {
copy_nonoverlapping(s.as_ptr(), ptr, len);
}
MyString { ptr, len, cap }
}
/// ่ฟๅๅญ็ฌฆไธฒๅ็
pub fn as_str(&self) -> &str {
// ๅฎๅ
จ๏ผptr..ptr+len ไน้ด็ๆฐๆฎๆฏๆๆ็ UTF-8
unsafe {
let slice = std::slice::from_raw_parts(self.ptr, self.len);
std::str::from_utf8_unchecked(slice)
}
}
/// ่ฟฝๅ ๅญ็ฌฆไธฒ
pub fn push_str(&mut self, s: &str) {
let new_len = self.len + s.len();
if new_len > self.cap {
self.grow(new_len);
}
unsafe {
copy_nonoverlapping(
s.as_ptr(),
self.ptr.add(self.len),
s.len(),
);
}
self.len = new_len;
}
/// ๆฉๅฎน
fn grow(&mut self, min_cap: usize) {
let new_cap = min_cap.max(self.cap * 2);
let old_layout = Layout::array::<u8>(self.cap).unwrap();
let new_layout = Layout::array::<u8>(new_cap).unwrap();
let new_ptr = unsafe { realloc(self.ptr, old_layout, new_layout.size()) };
if new_ptr.is_null() {
panic!("reallocation failed");
}
self.ptr = new_ptr;
self.cap = new_cap;
}
}
impl Drop for MyString {
fn drop(&mut self) {
// ้ๆพๅ ๅ
ๅญ
let layout = Layout::array::<u8>(self.cap).unwrap();
unsafe {
dealloc(self.ptr, layout);
}
// self.ptr ็ฐๅจๆฏๆฌๅๆ้๏ผไฝ MyString ๅณๅฐ่ขซ้ๆฏ
// ไธไผๆไปฃ็ ๅ่ฎฟ้ฎๅฎ
}
}
// Drop ่ขซ่ชๅจ่ฐ็จ๏ผ
fn demo() {
let s = MyString::from_str("hello");
// ... ไฝฟ็จ s ...
} // โ ่ฟ้่ชๅจ่ฐ็จ s.drop()
MyString ๆฒกๆๅฎ็ฐ Copy๏ผ่ฟๆๅณ็่ตๅผๆฏ move๏ผ
let s1 = MyString::from_str("hello");
let s2 = s1; // move๏ผ
// s1 ็ฐๅจๆ ๆ๏ผๅฆๆ s1 ่ฟ่ฝ็จ๏ผs1 ๅ s2 ็ drop ้ฝไผ้ๆพๅไธๅๅ
ๅญ
// โ double free โ ๆชๅฎไน่กไธบ
// Rust ็ผ่ฏๅจ้ปๆญขไฝ ไฝฟ็จ s1๏ผ
// println!("{:?}", s1); // โ use of moved value
impl Clone for MyString {
fn clone(&self) -> Self {
// ๆทฑๆท่ด๏ผๅ้
ๆฐ็ๅ ๅ
ๅญ๏ผๅคๅถๆฐๆฎ
MyString::from_str(self.as_str())
}
}
// ็ฐๅจ clone() ๅฏ็จ๏ผ
let s1 = MyString::from_str("hello");
let s2 = s1.clone(); // ๆพๅผๆทฑๆท่ด
// s1 ๅ s2 ้ฝๆๆ๏ผๅ่ชๆฅๆ็ฌ็ซ็ๅ ๅ
ๅญ
impl fmt::Display for MyString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl Deref for MyString {
type Target = str;
fn deref(&self) -> &Self::Target {
self.as_str()
}
}
impl DerefMut for MyString {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe {
let slice = std::slice::from_raw_parts_mut(self.ptr, self.len);
std::str::from_utf8_unchecked_mut(slice)
}
}
}
// Deref ่ฎฉ MyString ๅฏไปฅๅ &str ไธๆ ทไฝฟ็จ๏ผ
fn demo() {
let mut s = MyString::from_str("hello");
s.push_str(", world");
println!("{}", s); // Display
println!("len = {}", s.len()); // Deref ๅฐ str ็ len()
assert!(s.starts_with("hello")); // Deref ๅฐ str ็ๆนๆณ
}
โ
่ฆ็นๅ้กพ๏ผ้่ฟๅฎ็ฐ MyString๏ผๆไปฌ็ๅฐไบๆๆๆ็ณป็ป็ๅฎๆด้ญ็ฏโโalloc ๅ้
ๅ ๅ
ๅญ๏ผDrop ่ชๅจ้ๆพ๏ผMove ้ฒๆญข double free๏ผClone ๅ
่ฎธๆพๅผๆทฑๆท่ดใๆ ๅๅบ็ String ๅ็ไนๆฏ่ฟไบไบ๏ผๅชๆฏๆดๅฎๅ๏ผๅค็ไบ้ถๅคงๅฐ็ฑปๅใๅฏน้ฝ็ญ่พน็ๆ
ๅต๏ผใ