๐Ÿ”’ ๆ‰€ๆœ‰ๆƒไธŽๅ€Ÿ็”จ

Rust ๆœ€ๆ ธๅฟƒ็š„ๆฆ‚ๅฟตโ€”โ€”ๆ‰€ๆœ‰ๆƒใ€ๅ€Ÿ็”จใ€็”Ÿๅ‘ฝๅ‘จๆœŸใ€‚่ฟ™ๆ˜ฏ Rust ๅ’Œๅ…ถไป–่ฏญ่จ€ๆœ€ๆœฌ่ดจ็š„ๅŒบๅˆซ๏ผŒไนŸๆ˜ฏ็ผ–่ฏ‘ๅ™จ่ƒฝไฟ่ฏๅ†…ๅญ˜ๅฎ‰ๅ…จ็š„ๆ นๅŸบใ€‚็†่งฃๅฎƒ๏ผŒไฝ ๅฐฑ็†่งฃไบ† Rust ็š„ไธ€ๅˆ‡่ฎพ่ฎก้€‰ๆ‹ฉใ€‚

ๆ‰€ๆœ‰ๆƒ Move่ฏญไน‰ ๅ€Ÿ็”จ ็”Ÿๅ‘ฝๅ‘จๆœŸ ้›ถๆˆๆœฌๆŠฝ่ฑก

๐Ÿ“‘ ็›ฎๅฝ•

  1. ไธบไป€ไนˆ้œ€่ฆๆ‰€ๆœ‰ๆƒ
  2. ๆ‰€ๆœ‰ๆƒ่ง„ๅˆ™
  3. Move่ฏญไน‰่ฏฆ่งฃ
  4. ๅ€Ÿ็”จไธŽๅผ•็”จ
  5. ๆ‚ฌๅž‚ๅผ•็”จ
  6. ็”Ÿๅ‘ฝๅ‘จๆœŸๆ ‡ๆณจ
  7. ้™ๆ€็”Ÿๅ‘ฝๅ‘จๆœŸ
  8. ๅคๆ‚ๅœบๆ™ฏ
  9. ๅธธ่ง้™ท้˜ฑ
  10. ๅฎžๆˆ˜๏ผšๅฎž็Žฐไธ€ไธช็ฎ€ๅ•็š„String็ฑปๅž‹

1. ไธบไป€ไนˆ้œ€่ฆๆ‰€ๆœ‰ๆƒ

ๅ†…ๅญ˜็ฎก็†ๆ˜ฏ็ณป็ปŸ็ผ–็จ‹็š„ๆ ธๅฟƒ้šพ้ข˜ใ€‚ๅœจ Rust ไน‹ๅ‰๏ผŒไธš็•Œไธป่ฆ้‡‡็”จไธค็งๆ–นๆกˆ๏ผŒไฝ†้ƒฝๆœ‰ๆ˜Žๆ˜พ็š„้—ฎ้ข˜ใ€‚

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ ๅ†…ๅญ˜็ฎก็†็š„ไธ‰ๆก่ทฏ โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ ๆ‰‹ๅŠจ็ฎก็† โ”‚ ๅžƒๅœพๅ›žๆ”ถ(GC) โ”‚ ๆ‰€ๆœ‰ๆƒ็ณป็ปŸ โ”‚ โ”‚ C/C++ โ”‚ Java/Go/JS โ”‚ Rust โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ โœ… ้›ถๅผ€้”€ โ”‚ โœ… ๅฎ‰ๅ…จ โ”‚ โœ… ้›ถๅผ€้”€ โ”‚ โ”‚ โœ… ๅฏ้ข„ๆต‹ โ”‚ โœ… ๅผ€ๅ‘ๆ•ˆ็އ้ซ˜ โ”‚ โœ… ๅฎ‰ๅ…จ(็ผ–่ฏ‘ๆœŸไฟ่ฏ) โ”‚ โ”‚ โŒ ๆ‚ฌๅž‚ๆŒ‡้’ˆ โ”‚ โŒ Stop-the-worldโ”‚ โœ… ๅฏ้ข„ๆต‹ โ”‚ โ”‚ โŒ ไบŒๆฌก้‡Šๆ”พ โ”‚ โŒ ่ฟ่กŒๆ—ถๅผ€้”€ โ”‚ โŒ ๅญฆไน ๆ›ฒ็บฟ้™ก โ”‚ โ”‚ โŒ ๅ†…ๅญ˜ๆณ„ๆผ โ”‚ โŒ ๅปถ่ฟŸไธ็กฎๅฎš โ”‚ โ”‚ โ”‚ โŒ Use-after-freeโ”‚โŒ ๅ†…ๅญ˜ๅ ็”จ้ซ˜ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

C/C++ ็š„ๅ›ฐๅขƒ๏ผš่‡ช็”ฑไปฃไปท้ซ˜ๆ˜‚

C++
// ็ปๅ…ธ็š„ use-after-free
int* p = (int*)malloc(sizeof(int));
*p = 42;
free(p);
// ... ๅ‡ ็™พ่กŒไน‹ๅŽ ...
int x = *p;  // ๐Ÿ’ฅ ๆœชๅฎšไน‰่กŒไธบ๏ผŒๅฏ่ƒฝๅดฉ๏ผŒๅฏ่ƒฝไธๅดฉ๏ผŒๆœ€ๆๆ€–็š„ๆ˜ฏ"ๅฅฝๅƒ่ƒฝ่ท‘"

C++ ็จ‹ๅบๅ‘˜่Šฑๅคง้‡ๆ—ถ้—ด่ฐƒ่ฏ•ๅ†…ๅญ˜้—ฎ้ข˜ใ€‚Valgrindใ€AddressSanitizerใ€ๆ™บ่ƒฝๆŒ‡้’ˆโ€”โ€”่ฟ™ไบ›้ƒฝๆ˜ฏๅฏนๆ‰‹ๅŠจ็ฎก็†็ผบ้™ท็š„่กฅๆ•‘ๆŽชๆ–ฝ๏ผŒ่€Œ้žๆ นๆœฌ่งฃๅ†ณๆ–นๆกˆใ€‚

Go/Java ็š„ๅ›ฐๅขƒ๏ผšๅฎ‰ๅ…จ็š„ไปฃไปทๆ˜ฏ่ฟ่กŒๆ—ถ

Go
func process() *Data {
    d := &Data{...}
    // Go ็š„ GC ไผšๅœจๆŸไธชไธ็กฎๅฎš็š„ๆ—ถๅˆปๅ›žๆ”ถ
    // ไฝ† GC ้œ€่ฆ่ฟ่กŒๆ—ถ๏ผŒๅ ็”จ้ขๅค– 5-20% CPU
    // ไธ” STW(Stop-The-World) ๅฏผ่‡ดๅปถ่ฟŸๆŠ–ๅŠจ
    return d
}

Go ็š„ GC ่™ฝ็„ถไฝŽๅปถ่ฟŸ๏ผŒไฝ†ไป็„ถ๏ผš

Rust ็š„็ฌฌไธ‰ๆก่ทฏ๏ผš็ผ–่ฏ‘ๆœŸๆ‰€ๆœ‰ๆƒๆฃ€ๆŸฅ

Rust ็š„ๆดžๅฏŸๆ˜ฏ๏ผšๅ†…ๅญ˜ๅฎ‰ๅ…จ็š„่ง„ๅˆ™ๅฏไปฅๅœจ็ผ–่ฏ‘ๆœŸ้™ๆ€ๆฃ€ๆŸฅ๏ผŒ่€Œไธ้œ€่ฆ่ฟ่กŒๆ—ถ GCใ€‚ไปฃไปทๆ˜ฏ็จ‹ๅบๅ‘˜ๅฟ…้กปๅœจไปฃ็ ไธญๆ˜พๅผ่กจ่พพ"่ฐๆ‹ฅๆœ‰่ฟ™ๅ—ๅ†…ๅญ˜"โ€”โ€”ไฝ†่ฟ™ๆฐๆฐไฝฟๅพ—็จ‹ๅบๅ‘˜็š„ๆ„ๅ›พๆ›ดๆธ…ๆ™ฐใ€‚

๐Ÿ’ก ๆ ธๅฟƒๆ€ๆƒณ๏ผšๆ‰€ๆœ‰ๆƒไธๆ˜ฏ้™ๅˆถ๏ผŒๆ˜ฏๅฅ‘็บฆใ€‚ไฝ ๅ‘Š่ฏ‰็ผ–่ฏ‘ๅ™จ"่ฟ™ๅ—ๅ†…ๅญ˜ๅฝ’่ฐ็ฎก"๏ผŒ็ผ–่ฏ‘ๅ™จๅธฎไฝ ไฟ่ฏไธไผšๅ‡บ้—ฎ้ข˜ใ€‚ๅฆ‚ๆžœๅฅ‘็บฆไธๅˆ็†๏ผŒ็ผ–่ฏ‘ๅ™จๅœจ็ผ–่ฏ‘ๆœŸๅฐฑๆ‹’็ปไฝ ๏ผŒ่€Œไธๆ˜ฏๅœจ่ฟ่กŒๆ—ถๅดฉๆบƒใ€‚

2. ๆ‰€ๆœ‰ๆƒ่ง„ๅˆ™

Rust ็š„ๆ‰€ๆœ‰ๆƒ็ณป็ปŸๅปบ็ซ‹ๅœจไธ‰ๆก็ฎ€ๅ•่ง„ๅˆ™ไน‹ไธŠ๏ผš

โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๆ‰€ๆœ‰ๆƒไธ‰่ง„ๅˆ™ โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ่ง„ๅˆ™1 ๆฏไธชๅ€ผๆœ‰ไธ”ๅชๆœ‰ไธ€ไธช owner๏ผˆๆ‰€ๆœ‰่€…๏ผ‰ ่ง„ๅˆ™2 ๅŒไธ€ๆ—ถๅˆป๏ผŒๅ€ผๅช่ƒฝ่ขซไธ€ไธชๅ˜้‡ ๆ‹ฅๆœ‰ ่ง„ๅˆ™3 owner ็ฆปๅผ€ไฝœ็”จๅŸŸๆ—ถ๏ผŒๅ€ผ่ขซ ่‡ชๅŠจ้‡Šๆ”พ๏ผˆdrop๏ผ‰ โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

่ง„ๅˆ™1๏ผšๆฏไธชๅ€ผๅชๆœ‰ไธ€ไธช owner

Rust
let s = String::from("hello");
// s ๆ˜ฏ "hello" ่ฟ™ไธช String ๅ€ผ็š„ owner
// ๅชๆœ‰ไธ€ไธช owner๏ผŒๅฐฑๆ˜ฏ s
ๆ ˆ (Stack) ๅ † (Heap) โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ s โ”‚ โ”‚ h e l l o โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ โ”‚ โ”‚ โ”‚ โ”‚ ptr โ”‚โ”€โ”ผโ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ”‚ len: 5 โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ cap: 5 โ”‚ โ”‚ โ–ฒ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ๅชๆœ‰ไธ€ไธช owner ๆŒ‡ๅ‘่ฟ™ๅ—ๅ †ๅ†…ๅญ˜

่ง„ๅˆ™2๏ผš่ต‹ๅ€ผๆ˜ฏ่ฝฌ็งป๏ผˆMove๏ผ‰๏ผŒไธๆ˜ฏๅคๅˆถ

โœ… ๅฏไปฅ็ผ–่ฏ‘

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

่ง„ๅˆ™3๏ผš็ฆปๅผ€ไฝœ็”จๅŸŸ่‡ชๅŠจ้‡Šๆ”พ

Rust
fn main() {
    {
        let s = String::from("hello");
        // s ๅœจ่ฟ™ไธชไฝœ็”จๅŸŸๅ†…ๆœ‰ๆ•ˆ
    } // โ† s ็ฆปๅผ€ไฝœ็”จๅŸŸ๏ผŒ่‡ชๅŠจ่ฐƒ็”จ drop(s)
      //   ๅ †ไธŠ็š„ "hello" ่ขซ้‡Šๆ”พ๏ผŒๆ— ้œ€ๆ‰‹ๅŠจ free

    // println!("{}", s);  // โŒ s ไธๅญ˜ๅœจไบ†
}
ไฝœ็”จๅŸŸๅผ€ๅง‹ ไฝœ็”จๅŸŸ็ป“ๆŸ โ”‚ โ”‚ โ–ผ โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ let s = ... โ”‚ โ”‚ } โ”‚ โ”‚ โ”‚ โ”€โ”€โ”€โ–ถ โ”‚ drop(s) ่‡ชๅŠจ่ฐƒ็”จ โ”‚ โ”‚ s โ”€โ”€โ–ถ "hello" โ”‚ โ”‚ ๅ †ๅ†…ๅญ˜้‡Šๆ”พ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ๆ— ้œ€ๆ‰‹ๅŠจ free๏ผŒ็ผ–่ฏ‘ๅ™จๅœจไฝœ็”จๅŸŸ็ป“ๅฐพๆ’ๅ…ฅ drop ่ฐƒ็”จ

ไธŽ C++ ็š„ๅฏนๆฏ”

็‰นๆ€งC++ RAIIRust ๆ‰€ๆœ‰ๆƒ
่‡ชๅŠจๆžๆž„ๆžๆž„ๅ‡ฝๆ•ฐDrop trait
ๆ‹ท่ด่ฏญไน‰้ป˜่ฎคๆทฑๆ‹ท่ด้ป˜่ฎค move
ๆ‚ฌๅž‚ๅผ•็”จๅฏ่ƒฝๅ‘็”Ÿ็ผ–่ฏ‘ๆœŸ้˜ปๆญข
ๅŒ้‡้‡Šๆ”พๅฏ่ƒฝๅ‘็”Ÿไธๅฏ่ƒฝ(move ๅŽๅŽŸๅ˜้‡ๆ— ๆ•ˆ)
ๆ™บ่ƒฝๆŒ‡้’ˆunique_ptr/shared_ptrBox/Arc/Rc

3. Move่ฏญไน‰่ฏฆ่งฃ

Move ่ฏญไน‰ๆ˜ฏๆ‰€ๆœ‰ๆƒ็ณป็ปŸ็š„ๆ ธๅฟƒๆœบๅˆถใ€‚็†่งฃ move๏ผŒๅฐฑ็†่งฃไบ† Rust ไธบไป€ไนˆไธ้œ€่ฆ GCใ€‚

String ็š„ Move

String ็”ฑๆ ˆไธŠ็š„ๅ…ƒๆ•ฐๆฎ๏ผˆๆŒ‡้’ˆใ€้•ฟๅบฆใ€ๅฎน้‡๏ผ‰ๅ’Œๅ †ไธŠ็š„ๅฎž้™…ๆ•ฐๆฎ็ป„ๆˆใ€‚่ต‹ๅ€ผๆ—ถ๏ผŒๆ ˆไธŠ็š„ๅ…ƒๆ•ฐๆฎ่ขซๅคๅˆถ๏ผŒไฝ†ๅ †ๆ•ฐๆฎไธไผšโ€”โ€”ๅฆๅˆ™ไธคไธช owner ้ƒฝไผšๅฐ่ฏ•้‡Šๆ”พๅŒไธ€ๅ—ๅ†…ๅญ˜ใ€‚

let s1 = String::from("hello"); ๆ ˆ ๅ † โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ s1 โ”‚ โ”‚ h e l l o โ”‚ โ”‚ ptr โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถโ”‚ โ”‚ โ”‚ len: 5 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ cap: 5 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ let s2 = s1; // move๏ผไธๆ˜ฏ clone๏ผ ๆ ˆ ๅ † โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ s1 โ”‚ โ•ณ ๅทฒๅคฑๆ•ˆ โ”‚ h e l l o โ”‚ โ”‚ (invalid)โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ–ฒ โ”‚ s2 โ”‚ โ”‚ โ”‚ ptr โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ len: 5 โ”‚ โ”‚ cap: 5 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ s1 ๅคฑๆ•ˆ โ†’ ไธไผšไบŒๆฌก้‡Šๆ”พๅ †ๅ†…ๅญ˜ s2 ๆŽฅ็ฎก โ†’ ๅชๆœ‰ s2 ไผšๅœจ็ฆปๅผ€ไฝœ็”จๅŸŸๆ—ถ้‡Šๆ”พ

๐Ÿšซ ็ผ–่ฏ‘ๅ™จ่ฏดไธ่กŒ๏ผšlet s2 = s1; ไน‹ๅŽไฝฟ็”จ s1 ไผšๅพ—ๅˆฐ error[E0382]: use of moved value: s1ใ€‚่ฟ™ไธๆ˜ฏๅปบ่ฎฎ๏ผŒๆ˜ฏ็กฌๆ€ง็ผ–่ฏ‘้”™่ฏฏใ€‚

ๆ ˆๆ•ฐๆฎ็š„ Copy ่ฏญไน‰

ๅฆ‚ๆžœ็ฑปๅž‹็š„ๅ…จ้ƒจๆ•ฐๆฎ้ƒฝๅœจๆ ˆไธŠ๏ผŒไธ”ๅคๅˆถๆˆๆœฌไฝŽ๏ผŒRust ๅ…่ฎธๅฎƒๅฎž็Žฐ Copy traitใ€‚Copy ็ฑปๅž‹่ต‹ๅ€ผๆ—ถ่‡ชๅŠจๅคๅˆถ๏ผŒๅŽŸๅ˜้‡ไป็„ถๆœ‰ๆ•ˆใ€‚

Rust
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 ็ฑปๅž‹ โœ…้ž 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๏ผŒๅ› ไธบๅคšไธชไธๅฏๅ˜ๅผ•็”จๆ˜ฏๅ…่ฎธ็š„ใ€‚

clone()๏ผšๆ˜พๅผๆทฑๆ‹ท่ด

Rust
let s1 = String::from("hello");
let s2 = s1.clone();  // ๆ˜พๅผๆทฑๆ‹ท่ด๏ผŒๅ †ๆ•ฐๆฎไนŸ่ขซๅคๅˆถ
println!("s1 = {}, s2 = {}", s1, s2);  // โœ… ไธคไธช้ƒฝๆœ‰ๆ•ˆ
let s2 = s1.clone(); ๆ ˆ ๅ † โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ s1 โ”‚ โ”‚ h e l l o โ”‚ โ”‚ ptr โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถโ”‚ โ”‚ โ”‚ len: 5 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ cap: 5 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ h e l l o โ”‚ โ”‚ s2 โ”‚ โ”‚ (็‹ฌ็ซ‹็š„ๅ‰ฏๆœฌ) โ”‚ โ”‚ ptr โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถโ”‚ โ”‚ โ”‚ len: 5 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ cap: 5 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ไธคไปฝ็‹ฌ็ซ‹็š„ๅ †ๆ•ฐๆฎ๏ผŒๅ„่‡ช้‡Šๆ”พๅ„่‡ช็š„

ๅ‡ฝๆ•ฐไผ ๅ‚็š„ Move

ๆŠŠๅ€ผไผ ็ป™ๅ‡ฝๆ•ฐ๏ผŒๅ’Œ่ต‹ๅ€ผไธ€ๆ ทโ€”โ€”่ฆไนˆ move๏ผŒ่ฆไนˆ copyใ€‚

โœ… Copy ็ฑปๅž‹ไผ ๅ‚

fn print_i32(x: i32) {
    println!("{}", x);
}

let n = 42;
print_i32(n);
println!("{}", n); // โœ… n ไป็„ถๆœ‰ๆ•ˆ

โŒ ้ž Copy ็ฑปๅž‹ไผ ๅ‚

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

่งฃๅ†ณๅŠžๆณ•๏ผšไผ ๅผ•็”จ๏ผˆไธ‹ไธ€่Š‚่ฏฆ่ฟฐ๏ผ‰๏ผŒๆˆ–่€…ไผ ๆ‰€ๆœ‰ๆƒๅ†่ฟ”ๅ›žใ€‚

Rust
// ๆ–นๆกˆ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);  // โœ…

4. ๅ€Ÿ็”จไธŽๅผ•็”จ

ๅฆ‚ๆžœๆฏๆฌกไผ ๅ‚้ƒฝ่ฆ move ๅ†่ฟ”ๅ›ž๏ผŒไปฃ็ ไผš้žๅธธๅ•ฐๅ—ฆใ€‚Rust ็š„่งฃๅ†ณๆ–นๆกˆๆ˜ฏๅ€Ÿ็”จโ€”โ€”ๅˆ›ๅปบไธ€ไธชๆŒ‡ๅ‘ๅ€ผ็š„ๅผ•็”จ๏ผŒไฝ†ไธ่Žทๅ–ๆ‰€ๆœ‰ๆƒใ€‚

ไธๅฏๅ˜ๅผ•็”จ &T

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);
ไธๅฏๅ˜ๅผ•็”จ &T ๆ ˆ ๅ † โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ s1 โ”‚ โ”‚ &s1 โ”‚ โ”‚ h e l l o โ”‚ โ”‚ ptr โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ” โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ” โ”‚ โ”‚ โ”‚ len: 5 โ”‚ โ”‚ โ”‚ (ๅผ•็”จ) โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ cap: 5 โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ–ฒ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ &s1 ๅช่ƒฝ่ฏป๏ผŒไธ่ƒฝๆ”น๏ผŒไนŸไธ่ƒฝ้‡Šๆ”พ s1 ไป็„ถๆ˜ฏๅ”ฏไธ€็š„ๆ‰€ๆœ‰่€…

ๅฏๅ˜ๅผ•็”จ &mut T

Rust
fn add_world(s: &mut String) {
    s.push_str(", world");
}

let mut s = String::from("hello");
add_world(&mut s);
println!("{}", s);  // "hello, world"

ๅ€Ÿ็”จ่ง„ๅˆ™๏ผšRust ๆœ€้‡่ฆ็š„ๅฎ‰ๅ…จไฟ่ฏ

โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๅ€Ÿ็”จ่ง„ๅˆ™๏ผˆThe Alias + Mutability Rule๏ผ‰ โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๅ…่ฎธ๏ผšๅคšไธช &T๏ผˆๅคšไธช่ฏป่€…๏ผ‰ ๅ…่ฎธ๏ผšไธ€ไธช &mut T๏ผˆๅ”ฏไธ€ๅ†™่€…๏ผ‰ ็ฆๆญข๏ผš&T ๅ’Œ &mut T ๅŒๆ—ถๅญ˜ๅœจ๏ผˆ่ฏปๅ†™ๅ†ฒ็ช๏ผ‰ ็ฆๆญข๏ผšๅคšไธช &mut T ๅŒๆ—ถๅญ˜ๅœจ๏ผˆๅ†™ๅ†™ๅ†ฒ็ช๏ผ‰ ็ฎ€่ฎฐ๏ผš่ฆไนˆๅคšไธช่ฏป๏ผŒ่ฆไนˆไธ€ไธชๅ†™๏ผŒ็ปไธๅŒๆ—ถ โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

โœ… ๅคšไธชไธๅฏๅ˜ๅผ•็”จ

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");

NLL๏ผˆNon-Lexical Lifetimes๏ผ‰

Rust 2018 ๅผ•ๅ…ฅไบ† NLL๏ผŒๅผ•็”จ็š„็”Ÿๅ‘ฝๅ‘จๆœŸๅœจๆœ€ๅŽไธ€ๆฌกไฝฟ็”จๆ—ถ็ป“ๆŸ๏ผŒ่€Œไธๆ˜ฏๅœจไฝœ็”จๅŸŸ็ป“ๆŸๆ—ถใ€‚่ฟ™่ฎฉไปฃ็ ๆ›ด่‡ช็„ถ๏ผš

Rust
let mut s = String::from("hello");

let r1 = &s;
println!("{}", r1);   // r1 ๆœ€ๅŽไธ€ๆฌกไฝฟ็”จ

// r1 ็š„็”Ÿๅ‘ฝๅ‘จๆœŸๅœจๆญค็ป“ๆŸ๏ผˆNLL๏ผ‰๏ผŒๅณไฝฟไฝœ็”จๅŸŸๆœช็ป“ๆŸ
let r2 = &mut s;      // โœ… ๅœจ NLL ไธ‹ๅฏไปฅ็ผ–่ฏ‘
println!("{}", r2);

๐Ÿ’ก NLL ็š„ๆ„ไน‰๏ผšๅผ•็”จ็š„็”Ÿๅ‘ฝๅ‘จๆœŸไธๆ˜ฏ็œ‹่Šฑๆ‹ฌๅท๏ผŒ่€Œๆ˜ฏ็œ‹ๅฎž้™…ไฝฟ็”จไฝ็ฝฎใ€‚็ผ–่ฏ‘ๅ™จไผšๅˆ†ๆžๅผ•็”จ็š„"ๆดป่ทƒ่Œƒๅ›ด"๏ผŒๅชๅœจ็œŸๆญฃๅ†ฒ็ชๆ—ถๆŠฅ้”™ใ€‚่ฟ™่ฎฉๅคง้‡ไน‹ๅ‰ๆ— ๆณ•็ผ–่ฏ‘็š„ไปฃ็ ๅ˜ๅพ—ๅˆๆณ•ใ€‚

ไธŽ Go ็š„ๅฏนๆฏ”

็‰นๆ€งGoRust
ๅ…ฑไบซๅฏๅ˜็Šถๆ€ๅ…่ฎธ๏ผˆ้œ€ๅŠ ้”ไฟ่ฏๅฎ‰ๅ…จ๏ผ‰็ผ–่ฏ‘ๆœŸ็ฆๆญข
ๆ•ฐๆฎ็ซžไบ‰่ฟ่กŒๆ—ถๆฃ€ๆต‹ (race detector)็ผ–่ฏ‘ๆœŸๆถˆ้™ค
ๆŒ‡้’ˆๅฎ‰ๅ…จGC ไฟ่ฏไธๆ‚ฌๅž‚ๅ€Ÿ็”จ่ง„ๅˆ™ไฟ่ฏไธๆ‚ฌๅž‚
ๅนถๅ‘ๅฎ‰ๅ…จChannel / MutexSend + Sync + ๅ€Ÿ็”จ่ง„ๅˆ™

5. ๆ‚ฌๅž‚ๅผ•็”จ

ๆ‚ฌๅž‚ๅผ•็”จ๏ผˆ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
ๆ‚ฌๅž‚ๅผ•็”จไธบไป€ไนˆๅฑ้™ฉ ๅ‡ฝๆ•ฐๆ‰ง่กŒๆ—ถ๏ผš ๅ‡ฝๆ•ฐ่ฟ”ๅ›žๅŽ๏ผš โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ ๆ ˆๅธง โ”‚ โ”‚ ๆ ˆๅธงๅทฒ่ขซๅ›žๆ”ถ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ s โ”‚ โ”‚ โ”‚ โ”‚ ๏ผŸ๏ผŸ๏ผŸ๏ผŸ๏ผŸ โ”‚ โ”‚ โ”‚ โ”‚ ptr โ”€โ”€โ–ถ "hello" โ”‚ โ”‚ โ”‚ ๆŒ‡ๅ‘ๅ“ช้‡Œ๏ผŸ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ &s โ”€โ”€โ–ถ s โ”‚ โ”‚ &s โ”€โ”€โ–ถ ๐Ÿ’€ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ C/C++๏ผšๅฏ่ƒฝไธๆŠฅ้”™๏ผŒ่ฟ่กŒๆ—ถๆ•ฐๆฎๆŸๅ Rust๏ผš็ผ–่ฏ‘ๅ™จ็›ดๆŽฅๆ‹’็ป๏ผŒไธๅฏ่ƒฝ่ฟ่กŒ

ไธŽ C++ ็š„ๅฏนๆฏ”

C++
// C++ ไธญ่ฟ™ๆฎตไปฃ็ ่ƒฝ็ผ–่ฏ‘๏ผŒไฝ†่ฟ่กŒๆ—ถๆœชๅฎšไน‰่กŒไธบ
std::string& dangling() {
    std::string s = "hello";
    return s;  // ่ฟ”ๅ›žๅฑ€้ƒจๅ˜้‡็š„ๅผ•็”จ
}  // s ่ขซ้”€ๆฏ๏ผŒๅผ•็”จๆ‚ฌๅž‚
// ่ฐƒ็”จ่€…ๅพ—ๅˆฐไธ€ไธชๆ‚ฌๅž‚ๅผ•็”จโ€”โ€”ๅฏ่ƒฝ"ๆญฃๅธธๅทฅไฝœ"๏ผŒไนŸๅฏ่ƒฝๅดฉๆบƒ

๐Ÿšซ ็ผ–่ฏ‘ๅ™จ่ฏดไธ่กŒ๏ผšRust ็ผ–่ฏ‘ๅ™จ็œ‹ๅˆฐ -> &String ไฝ†ๅ‡ฝๆ•ฐไฝ“ๅ†…ๆฒกๆœ‰ๅฏไปฅไปŽๅ‚ๆ•ฐๅ€Ÿ็”จ็š„ๅ€ผ๏ผŒ็›ดๆŽฅๆŠฅ้”™ missing lifetime specifierใ€‚ไฝ ๅฟ…้กป่ฆไนˆ่ฟ”ๅ›žๆ‹ฅๆœ‰ๆ‰€ๆœ‰ๆƒ็š„ String๏ผŒ่ฆไนˆไปŽๅ‚ๆ•ฐไธญๅ€Ÿ็”จโ€”โ€”็ผ–่ฏ‘ๅ™จไผš้ชŒ่ฏๅ€Ÿ็”จ็š„ๅˆๆณ•ๆ€งใ€‚

6. ็”Ÿๅ‘ฝๅ‘จๆœŸๆ ‡ๆณจ

ๅฝ“ๅ‡ฝๆ•ฐๆŽฅๅ—ๅผ•็”จๅ‚ๆ•ฐๅนถ่ฟ”ๅ›žๅผ•็”จๆ—ถ๏ผŒ็ผ–่ฏ‘ๅ™จ้œ€่ฆ็Ÿฅ้“่ฟ”ๅ›ž็š„ๅผ•็”จๅ’Œๅ“ชไธช่พ“ๅ…ฅๅผ•็”จๅ…ณ่”ใ€‚็”Ÿๅ‘ฝๅ‘จๆœŸๆ ‡ๆณจๅฐฑๆ˜ฏๅ‘Š่ฏ‰็ผ–่ฏ‘ๅ™จ่ฟ™ไธชๅ…ณ่”ๅ…ณ็ณปใ€‚

ไธบไป€ไนˆ้œ€่ฆ็”Ÿๅ‘ฝๅ‘จๆœŸๆ ‡ๆณจ

Rust
fn longest(x: &str, y: &str) -> &str {
    if x.len() > y.len() { x } else { y }
}
// โŒ ็ผ–่ฏ‘ๅ™จไธ็Ÿฅ้“่ฟ”ๅ›žๅ€ผๅผ•็”จ็š„ๆ˜ฏ x ่ฟ˜ๆ˜ฏ y
// ๅฆ‚ๆžœ x/y ็š„ๅฎž้™…็”Ÿๅ‘ฝๅ‘จๆœŸไธๅŒ๏ผŒๅฏ่ƒฝไบง็”Ÿๆ‚ฌๅž‚ๅผ•็”จ
้—ฎ้ข˜ๅœบๆ™ฏ ่ฐƒ็”จ๏ผšlongest(&s1, &s2) ๆ—ถ้—ด โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ s1 โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ s2 โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ ่ฟ”ๅ›ž๏ผŸ ?????????????????????โ–ˆโ–ˆโ–ˆ ๅฆ‚ๆžœ่ฟ”ๅ›ž็š„ๆ˜ฏ x ็š„ๅผ•็”จ๏ผŒไฝ† x ๆฏ” y ๆดปๅพ—ไน… โ†’ ๆฒก้—ฎ้ข˜ ๅฆ‚ๆžœ่ฟ”ๅ›ž็š„ๆ˜ฏ y ็š„ๅผ•็”จ๏ผŒไฝ† y ๆฏ” s1 ๅ…ˆๆญป โ†’ ๆ‚ฌๅž‚ๅผ•็”จ๏ผ ็ผ–่ฏ‘ๅ™จๆ— ๆณ•ๅœจ็ผ–่ฏ‘ๆœŸ็กฎๅฎš่ฟ”ๅ›ž็š„ๆ˜ฏ x ่ฟ˜ๆ˜ฏ y โ†’ ้œ€่ฆ็จ‹ๅบๅ‘˜็”จ็”Ÿๅ‘ฝๅ‘จๆœŸๆ ‡ๆณจๆฅๅฃฐๆ˜Žๅ…ณ็ณป

็”Ÿๅ‘ฝๅ‘จๆœŸ่ฏญๆณ• 'a

็”Ÿๅ‘ฝๅ‘จๆœŸๅ‚ๆ•ฐ็”จ 'aใ€'b ็ญ‰่กจ็คบ๏ผŒๅ†™ๅœจ & ๅŽ้ขใ€‚ๅฎƒไปฌไธๆ”นๅ˜ไปปไฝ•ๅผ•็”จ็š„ๅฎž้™…็”Ÿๅ‘ฝๅ‘จๆœŸ๏ผŒๅชๆ˜ฏๆ่ฟฐๅผ•็”จไน‹้—ด็š„ๅ…ณ็ณปใ€‚

Rust
// ๅ‘Š่ฏ‰็ผ–่ฏ‘ๅ™จ๏ผš่ฟ”ๅ›žๅ€ผ็š„็”Ÿๅ‘ฝๅ‘จๆœŸ่‡ณๅฐ‘ๅ’Œ 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
}
็”Ÿๅ‘ฝๅ‘จๆœŸ 'a ็š„ๅซไน‰ fn longest<'a>(x: &'a str, y: &'a str) -> &'a str ่งฃ่ฏป๏ผš โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ x ๆดป 'a ไน… โ”‚ โ”‚ y ๆดป 'a ไน… โ”‚ โ”‚ ่ฟ”ๅ›žๅ€ผ่‡ณๅฐ‘ๆดป 'a ไน… โ”‚ โ”‚ โ”‚ โ”‚ 'a = min(x็š„็”Ÿๅ‘ฝๅ‘จๆœŸ, y็š„็”Ÿๅ‘ฝๅ‘จๆœŸ) โ”‚ โ”‚ ่ฟ”ๅ›žๅ€ผไธไผšๆฏ”ๆœ€็Ÿญ็š„่พ“ๅ…ฅๆดปๅพ—ๆ›ดไน… โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ๅฎž้™…ไธŠ 'a ๆ˜ฏ่ฐƒ็”จ่€…็บฆๆŸ็š„๏ผŒ็ผ–่ฏ‘ๅ™จไผšๅœจๆฏไธช่ฐƒ็”จ็‚น้ชŒ่ฏ

็ป“ๆž„ไฝ“ไธญ็š„็”Ÿๅ‘ฝๅ‘จๆœŸ

็ป“ๆž„ไฝ“ๅฆ‚ๆžœๆŒๆœ‰ๅผ•็”จ๏ผŒๅฟ…้กปๆ ‡ๆณจ็”Ÿๅ‘ฝๅ‘จๆœŸโ€”โ€”ๅ‘Š่ฏ‰็ผ–่ฏ‘ๅ™จ่ฟ™ไธชๅผ•็”จ่‡ณๅฐ‘ๆดปๅคšไน…ใ€‚

โœ… ๆ ‡ๆณจ็”Ÿๅ‘ฝๅ‘จๆœŸ

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]๏ผ‰ใ€‚ๆŒๆœ‰ๅผ•็”จๆ„ๅ‘ณ็€็ป“ๆž„ไฝ“็š„็”Ÿๅ‘ฝๅ‘จๆœŸๅ—้™ไบŽๅผ•็”จ็›ฎๆ ‡๏ผŒ่ฟ™ไผšๅคงๅน…้™ๅˆถ็ตๆดปๆ€งใ€‚ๅชๅœจๆ€ง่ƒฝๅ…ณ้”ฎ่ทฏๅพ„ๆˆ–้›ถๆ‹ท่ดๅœบๆ™ฏไธญไฝฟ็”จๅผ•็”จๅญ—ๆฎตใ€‚

็”Ÿๅ‘ฝๅ‘จๆœŸ็œ็•ฅ่ง„ๅˆ™๏ผˆElision Rules๏ผ‰

็ผ–่ฏ‘ๅ™จๅœจ็ฎ€ๅ•ๅœบๆ™ฏไธ‹ๅฏไปฅ่‡ชๅŠจๆŽจๆ–ญ็”Ÿๅ‘ฝๅ‘จๆœŸ๏ผŒไธ้œ€่ฆๆ‰‹ๅŠจๆ ‡ๆณจใ€‚ไธ‰ๆก็œ็•ฅ่ง„ๅˆ™๏ผš

โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ็”Ÿๅ‘ฝๅ‘จๆœŸ็œ็•ฅไธ‰่ง„ๅˆ™ โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ่ง„ๅˆ™1๏ผˆ่พ“ๅ…ฅ๏ผ‰๏ผšๆฏไธชๅผ•็”จๅ‚ๆ•ฐ่Žทๅพ—่‡ชๅทฑ็š„็”Ÿๅ‘ฝๅ‘จๆœŸ fn foo(x: &str, y: &str) โ†’ fn foo<'a, 'b>(x: &'a str, y: &'b str) ่ง„ๅˆ™2๏ผˆ่พ“ๅ‡บ๏ผ‰๏ผšๅฆ‚ๆžœๆฐๅฅฝไธ€ไธช่พ“ๅ…ฅ็”Ÿๅ‘ฝๅ‘จๆœŸ๏ผŒ่พ“ๅ‡บๅŒๅฎƒ fn foo(x: &str) -> &str โ†’ fn foo<'a>(x: &'a str) -> &'a str ่ง„ๅˆ™3๏ผˆๆ–นๆณ•๏ผ‰๏ผšๅคšไธช่พ“ๅ…ฅไฝ†ๅซ &self/&mut self๏ผŒ ่พ“ๅ‡บๅŒ self fn method(&self, x: &str) -> &str โ†’ fn method<'a, 'b>(&'a self, x: &'b str) -> &'a str โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
Rust
// ็œ็•ฅๅ†™ๆณ•๏ผˆ็ผ–่ฏ‘ๅ™จ่‡ชๅŠจๆŽจๆ–ญ๏ผ‰
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 {
    // ...
}

7. ้™ๆ€็”Ÿๅ‘ฝๅ‘จๆœŸ

'static ๆ˜ฏไธ€ไธช็‰นๆฎŠ็š„็”Ÿๅ‘ฝๅ‘จๆœŸ๏ผŒ่กจ็คบๅผ•็”จๅœจๆ•ดไธช็จ‹ๅบ่ฟ่กŒๆœŸ้—ด้ƒฝๆœ‰ๆ•ˆใ€‚

ๅญ—็ฌฆไธฒๅญ—้ข้‡

Rust
let s: &'static str = "hello world";
// ๅญ—็ฌฆไธฒๅญ—้ข้‡็›ดๆŽฅ็ผ–่ฏ‘่ฟ›ไบŒ่ฟ›ๅˆถๆ–‡ไปถ๏ผŒๆฐธไธ่ฟ‡ๆœŸ
'static ็š„ไธค็งๅซไน‰ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ 1. ๅผ•็”จ็”Ÿๅ‘ฝๅ‘จๆœŸ๏ผšๅผ•็”จๅœจๆ•ดไธช็จ‹ๅบ่ฟ่กŒๆœŸ้—ด้ƒฝๆœ‰ๆ•ˆ โ”‚ โ”‚ โ†’ ๅญ—็ฌฆไธฒๅญ—้ข้‡ๅญ˜ๅœจไบŒ่ฟ›ๅˆถ็š„ .rodata ๆฎต โ”‚ โ”‚ โ†’ ็จ‹ๅบ็ป“ๆŸๅ‰ไธไผšๅ›žๆ”ถ โ”‚ โ”‚ โ”‚ โ”‚ 2. ๆณ›ๅž‹็บฆๆŸ๏ผšT: 'static โ”‚ โ”‚ โ†’ T ไธๅซไปปไฝ•้ž 'static ็š„ๅผ•็”จ โ”‚ โ”‚ โ†’ T ๅฏไปฅๅฎ‰ๅ…จๅœฐๆดปๅˆฐ็จ‹ๅบ็ป“ๆŸ โ”‚ โ”‚ โ†’ โš ๏ธ ไธ็ญ‰ไบŽ T ๅฟ…้กปๆดปๅˆฐ็จ‹ๅบ็ป“ๆŸ๏ผ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

T: 'static ไธ็ญ‰ไบŽ"ๆฐธ่ฟœๆดป็€"

โš ๏ธ ๅธธ่ง่ฏฏ่งฃ๏ผšT: 'static ่กจ็คบ T ไธญไธๅซไปปไฝ•็ŸญไบŽ 'static ็š„ๅผ•็”จ๏ผŒ่€Œ้ž T ๆœฌ่บซๅฟ…้กปๆดปๅˆฐ็จ‹ๅบ็ป“ๆŸใ€‚ๆ‰€ๆœ‰ๆ‹ฅๆœ‰ๆ‰€ๆœ‰ๆƒ็š„็ฑปๅž‹๏ผˆๅฆ‚ Stringใ€Vec<T>๏ผ‰้ƒฝๆปก่ถณ T: 'static๏ผŒๅ› ไธบๅฎƒไปฌไธไพ่ต–ๅค–้ƒจๅผ•็”จใ€‚

Rust
// 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
}

'static ็š„ๅ…ธๅž‹ไฝฟ็”จๅœบๆ™ฏ

8. ๅคๆ‚ๅœบๆ™ฏ

็ป“ๆž„ไฝ“ไธญ็š„ๅคšไธช็”Ÿๅ‘ฝๅ‘จๆœŸ

ๅฝ“็ป“ๆž„ไฝ“ๆŒๆœ‰ๆฅ่‡ชไธๅŒๆฅๆบ็š„ๅผ•็”จๆ—ถ๏ผŒ้œ€่ฆไธๅŒ็š„็”Ÿๅ‘ฝๅ‘จๆœŸๅ‚ๆ•ฐ๏ผš

Rust
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
    }
}
ๅคšไธช็”Ÿๅ‘ฝๅ‘จๆœŸ็š„ๆ„ไน‰ ๆ—ถ้—ด โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ config โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ input โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ Context โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ (input ๅ’Œ config ็š„ไบค้›†) ่ฟ”ๅ›ž &'input โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ (ๅช็ป‘ๅฎš input๏ผŒไธๅ— config ้™ๅˆถ) ๅˆ†็ฆป็”Ÿๅ‘ฝๅ‘จๆœŸ โ†’ ่ฟ”ๅ›žๅ€ผไธๅ—ไธ็›ธๅ…ณๅผ•็”จ็š„้™ๅˆถ

็”Ÿๅ‘ฝๅ‘จๆœŸ็บฆๆŸ๏ผˆLifetime Bounds๏ผ‰

Rust
// 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 Bound๏ผˆHRTB๏ผ‰

ๅฏนไบŽ้—ญๅŒ…ๅ’Œ trait ไธญ็š„็”Ÿๅ‘ฝๅ‘จๆœŸ๏ผŒๆœ‰ๆ—ถ้œ€่ฆ"ๅฏนๆ‰€ๆœ‰็”Ÿๅ‘ฝๅ‘จๆœŸ้ƒฝๆˆ็ซ‹"็š„็บฆๆŸ๏ผš

Rust
// 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 ่ฎพ่ฎกไธญ๏ผŒ็‰นๅˆซๆ˜ฏๆถ‰ๅŠ้—ญๅŒ…ๅ’Œๅ›ž่ฐƒ็š„ๅœบๆ™ฏใ€‚ๅฆ‚ๆžœไฝ ้‡ๅˆฐไบ†๏ผŒๅคงๆฆ‚็އๅฏไปฅ็”จๆ›ด็ฎ€ๅ•็š„ๆ–นๅผ้‡ๅ†™ใ€‚

9. ๅธธ่ง้™ท้˜ฑ

้™ท้˜ฑ1๏ผšๅŒๆ—ถๆŒๆœ‰ๅผ•็”จๅ’Œๅฏๅ˜ๅผ•็”จ

โŒ ็ผ–่ฏ‘ๅคฑ่ดฅ

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);
ไธบไป€ไนˆ push ๅ’Œ &v[0] ๅ†ฒ็ช๏ผŸ push ไน‹ๅ‰๏ผš push ไน‹ๅŽ๏ผˆๅฏ่ƒฝ้‡ๆ–ฐๅˆ†้…๏ผ‰๏ผš โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ v โ”‚ โ”‚ v โ”‚ โ”‚ ptrโ”€โ”€โ”ผโ”€โ”€โ–ถ [1,2,3,4,5] โ”‚ ptrโ”€โ”€โ”ผโ”€โ”€โ–ถ [1,2,3,4,5,6] (ๆ–ฐๅœฐๅ€) โ”‚ cap:5โ”‚ โ”‚ cap:8โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ–ฒ ๆ—งๅ†…ๅญ˜ๅทฒ้‡Šๆ”พ๏ผ โ”‚ first โ†’ ๐Ÿ’€ ๆ‚ฌๅž‚ๅผ•็”จ first โ”€โ”˜ Vec push ๅฏ่ƒฝ realloc โ†’ ๆ—งๆŒ‡้’ˆๆ‚ฌๅž‚ โ†’ ๅ€Ÿ็”จ่ง„ๅˆ™้˜ปๆญข

้™ท้˜ฑ2๏ผš่‡ชๅผ•็”จ็ป“ๆž„

Rust
// โŒ ๆ— ๆณ•็›ดๆŽฅ่กจ่พพ่‡ชๅผ•็”จ
struct SelfRef {
    data: String,
    pointer: &str,  // ๆƒณๆŒ‡ๅ‘ data๏ผŒไฝ†็”Ÿๅ‘ฝๅ‘จๆœŸๆ€Žไนˆๅ†™๏ผŸ
}

// ๅฐ่ฏ•1๏ผš็”Ÿๅ‘ฝๅ‘จๆœŸๆ ‡ๆณจ
struct SelfRef2<'a> {
    data: String,
    pointer: &'a str,  // 'a ไปŽๅ“ชๆฅ๏ผŸ
}
// ๆ— ๆณ•ๅˆ›ๅปบ๏ผๅ› ไธบ data ็š„ๅœฐๅ€ๅœจๆž„้€ ๅŽๆ‰็Ÿฅ้“๏ผŒ
// ่€Œ 'a ้œ€่ฆๅœจๆž„้€ ๆ—ถ็กฎๅฎš

่‡ชๅผ•็”จ็ป“ๆž„ๅœจ Rust ไธญๆ˜ฏไธช็ปๅ…ธ้šพ้ข˜ใ€‚่งฃๅ†ณๆ–นๆกˆ๏ผš

ๆ–นๆกˆๅŽŸ็†้€‚็”จๅœบๆ™ฏ
Pin<Box<T>>ไฟ่ฏๆ•ฐๆฎไธไผš่ขซ moveasync/await ็”Ÿๆˆ็š„ Future
็ดขๅผ•ๆ›ฟไปฃๅผ•็”จ็”จ usize ็ดขๅผ•ไปฃๆ›ฟๆŒ‡้’ˆslotmap / arena
owning_ref crateๅฐ่ฃ…ๅฎ‰ๅ…จ็š„่‡ชๅผ•็”จ้œ€่ฆ่‡ชๅผ•็”จ็š„ๅฎนๅ™จ
rental crateๅฃฐๆ˜Žๅผ่‡ชๅผ•็”จๅคๆ‚่‡ชๅผ•็”จๅœบๆ™ฏ๏ผˆๅทฒๅผƒ็”จ๏ผ‰
้‡ๆ–ฐ่ฎพ่ฎก้ฟๅ…่‡ชๅผ•็”จๅคงๅคšๆ•ฐๆƒ…ๅ†ตไธ‹ๆœ€ไฝณ
Rust โ€” ็ดขๅผ•ๆ›ฟไปฃๅผ•็”จ
// ็”จ็ดขๅผ•ไปฃๆ›ฟๅผ•็”จ๏ผŒ็ป•่ฟ‡็”Ÿๅ‘ฝๅ‘จๆœŸ้—ฎ้ข˜
struct SelfRefIndexed {
    data: Vec<String>,
    pointer_idx: usize,  // ๆŒ‡ๅ‘ data[pointer_idx]
}

impl SelfRefIndexed {
    fn get_ref(&self) -> &str {
        &self.data[self.pointer_idx]
    }
}

้™ท้˜ฑ3๏ผšๅพช็Žฏๅผ•็”จ

Rust ็š„ๆ‰€ๆœ‰ๆƒๆจกๅž‹ๅคฉ็„ถ้˜ฒๆญขไบ†ๅพช็Žฏๅผ•็”จๅฏผ่‡ด็š„ๅ†…ๅญ˜ๆณ„ๆผโ€”โ€”ไฝ†ๅฆ‚ๆžœไฝ ็”จ Rc/Arc๏ผŒๅพช็Žฏๅผ•็”จไป็„ถๅฏ่ƒฝๅ‘็”Ÿ๏ผš

Rc ๅพช็Žฏๅผ•็”จๅฏผ่‡ดๅ†…ๅญ˜ๆณ„ๆผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Node A โ”‚ โ”‚ Rc(1) โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ–ฒ โ–ผ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ Node B โ”‚ โ”‚ Rc(1) โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ A ็š„ๅผ•็”จ่ฎกๆ•ฐ = 1 (B ๅผ•็”จ A) B ็š„ๅผ•็”จ่ฎกๆ•ฐ = 1 (A ๅผ•็”จ B) ไธค่€…ไบ’็›ธๅผ•็”จ โ†’ ๅผ•็”จ่ฎกๆ•ฐๆฐธไธไธบ 0 โ†’ ๅ†…ๅญ˜ๆณ„ๆผ๏ผ
Rust โ€” ็”จ Weak ๆ‰“็ ดๅพช็Žฏ
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 ่ขซ้‡Šๆ”พ
Weak ๆ‰“็ ดๅพช็Žฏ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ branch โ”‚ โ”‚ Rc(1) โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Strong โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ–ฒ โ–ผ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” Weak โ”‚ leaf โ”‚ (ไธๅขžๅŠ ่ฎกๆ•ฐ) โ”‚ Rc(1) โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ branch ็š„ๅผ•็”จ่ฎกๆ•ฐ = 1๏ผˆๅชๆœ‰ๅค–้ƒจๅ˜้‡ๆŒๆœ‰๏ผ‰ ๅค–้ƒจ branch ็ฆปๅผ€ไฝœ็”จๅŸŸ โ†’ branch ่ขซ้‡Šๆ”พ โ†’ leaf ็š„ Weak ๅ˜ๆˆ None

้™ท้˜ฑ4๏ผš็ป“ๆž„ไฝ“ๆ›ดๆ–ฐ่ฏญๆณ•ไธญ็š„ Move

Rust
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 ็ฑปๅž‹

10. ๅฎžๆˆ˜๏ผšๅฎž็Žฐไธ€ไธช็ฎ€ๅ•็š„ String ็ฑปๅž‹

้€š่ฟ‡ไปŽ้›ถๅฎž็Žฐไธ€ไธช็ฎ€ๅŒ–็‰ˆ MyString๏ผŒๆทฑๅ…ฅ็†่งฃๆ‰€ๆœ‰ๆƒใ€moveใ€drop ็š„ๅบ•ๅฑ‚ๆœบๅˆถใ€‚

็ฌฌไธ€ๆญฅ๏ผšๅฎšไน‰็ป“ๆž„

Rust
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;
    }
}

็ฌฌไบŒๆญฅ๏ผšๅฎž็Žฐ Drop โ€” ่‡ชๅŠจ้‡Šๆ”พ

Rust
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()

็ฌฌไธ‰ๆญฅ๏ผš็†่งฃ Move ็š„ๅ…ณ้”ฎ

MyString ๆฒกๆœ‰ๅฎž็Žฐ Copy๏ผŒ่ฟ™ๆ„ๅ‘ณ็€่ต‹ๅ€ผๆ˜ฏ move๏ผš

Rust
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
Move ไธบไป€ไนˆๆ˜ฏ้ป˜่ฎค่กŒไธบ๏ผŸ ๅฆ‚ๆžœ่ต‹ๅ€ผๆ˜ฏๅคๅˆถ๏ผˆๆทฑๆ‹ท่ด๏ผ‰๏ผš โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ s1 โ”‚ โ”‚ h e l l o โ”‚ โ”‚ ptr โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถโ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ s2 โ”‚ โ”‚ h e l l o โ”‚ โ† ๆตช่ดน๏ผ โ”‚ ptr โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถโ”‚ (ๆ‹ท่ด) โ”‚ ๆฏๆฌก่ต‹ๅ€ผ้ƒฝๆทฑๆ‹ท่ด โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ๆ€ง่ƒฝๅพˆๅทฎ ๅฆ‚ๆžœ่ต‹ๅ€ผๆ˜ฏๆต…ๆ‹ท่ด๏ผˆๅƒ C++ ็š„ๆต…ๆ‹ท่ด๏ผ‰๏ผš โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ s1 โ”‚ โ”Œโ”€โ”€โ”€โ–ถ โ”‚ h e l l o โ”‚ โ”‚ ptr โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ–ฒ โ”‚ s2 โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ ptr โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”˜ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ double free๏ผไธคไธช drop ้ƒฝไผš้‡Šๆ”พ Rust ็š„ Move๏ผšๆต…ๆ‹ท่ด + ไฝฟๅŽŸๅ˜้‡ๅคฑๆ•ˆ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ s1 โ”‚ โ•ณ ๅคฑๆ•ˆ โ”‚ h e l l o โ”‚ โ”‚ (moved) โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ–ฒ โ”‚ s2 โ”‚ โ”‚ โ”‚ ptr โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ๅชๆœ‰ไธ€ไธช owner โ†’ ๅชไผš drop ไธ€ๆฌก โ†’ ๅฎ‰ๅ…จไธ”้ซ˜ๆ•ˆ

็ฌฌๅ››ๆญฅ๏ผšๅฎž็Žฐ Clone

Rust
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 ้ƒฝๆœ‰ๆ•ˆ๏ผŒๅ„่‡ชๆ‹ฅๆœ‰็‹ฌ็ซ‹็š„ๅ †ๅ†…ๅญ˜

็ฌฌไบ”ๆญฅ๏ผšๅฎŒๆ•ดๅฎž็Žฐๆฆ‚่งˆ

Rust
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 ๅš็š„ไนŸๆ˜ฏ่ฟ™ไบ›ไบ‹๏ผŒๅชๆ˜ฏๆ›ดๅฎŒๅ–„๏ผˆๅค„็†ไบ†้›ถๅคงๅฐ็ฑปๅž‹ใ€ๅฏน้ฝ็ญ‰่พน็•Œๆƒ…ๅ†ต๏ผ‰ใ€‚

๐ŸŽฏ ๆ ธๅฟƒ่ฆ็‚นๆ€ป็ป“

3
ๆ‰€ๆœ‰ๆƒ่ง„ๅˆ™
2
ๅผ•็”จ็ฑปๅž‹ &T / &mut T
1
ๅ€Ÿ็”จๅŽŸๅˆ™๏ผšๅคš่ฏปๆˆ–ไธ€ๅ†™
3
็”Ÿๅ‘ฝๅ‘จๆœŸ็œ็•ฅ่ง„ๅˆ™
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๆ‰€ๆœ‰ๆƒๆ€็ปดๅฏผๅ›พ โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๆ‰€ๆœ‰ๆƒ็ณป็ปŸ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ ๆ‰€ๆœ‰ๆƒ ๅ€Ÿ็”จ โ”Œโ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ โ”‚ Move Copy &T &mut T โ”‚ โ”‚ โ”‚ โ”‚ ้ž Copy Copy ๅคšไธช่ฏป ๅ”ฏไธ€ๅ†™ ็ฑปๅž‹ ็ฑปๅž‹ ๅŒๆ—ถOK ๅŒๆ—ถๅˆปๅชๆœ‰ไธ€ไธช ่ต‹ๅ€ผ= ่ต‹ๅ€ผ= ่ฝฌ็งป ๅคๅˆถ ็”Ÿๅ‘ฝๅ‘จๆœŸ 'a โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ ็œ็•ฅ่ง„ๅˆ™ ๆ˜พๅผๆ ‡ๆณจ (่‡ชๅŠจๆŽจๆ–ญ) (ๅคๆ‚ๅœบๆ™ฏ) โ”‚ โ”‚ ่พ“ๅ…ฅโ†’่พ“ๅ‡บ ๅ‡ฝๆ•ฐ/็ป“ๆž„ไฝ“/ selfโ†’่ฟ”ๅ›ž ๅคš็”Ÿๅ‘ฝๅ‘จๆœŸ็บฆๆŸ โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•