Berbagi teknologi

Hari ke-2 Berlatih bahasa Rust dengan Semantik Rustling-Move

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Halo semuanya

Hari ini saya menyelesaikan Kamp Pelatihan Pengembangan OS Mengemudi Otonom 2024 - Kamp Dasar Tahap Keempat - Tutorial

Hari ke-2 Berlatih bahasa Rust dengan Semantik Rustling-Move

tinggi
tinggi
tinggi

https://doc.rust-lang.org/stable/book/ch04-00-memahami-kepemilikan.html

Ketika saya mengirimkan kode, saya mendapat pesan bahwa saya tidak memiliki izin. Bagaimana cara saya keluar?

tinggi
tinggi

tindakan

tinggi

Konfigurasi lingkungan pengembangan referensi

https://rcore-os.cn/buku-tutorial-arceos/ch01-02.html

topik saya

https://github.com/cicvedu/rustlings-semester-4-poin-perhatian

Buat kunci ssh untuk mengkloning kode github melalui ssh. Di lingkungan Linux, gunakan perintah ssh-keygen -t rsa -b 4096 -C "kotak surat Anda" untuk membuat kunci ssh. Cukup tekan Enter untuk semua opsi berikut. Kemudian gunakan cat ~/.ssh/id_rsa.pub

Tipe Primitif

Rust memiliki beberapa tipe dasar yang langsung diimplementasikan ke dalam kompiler. Di bagian ini, kita akan membahas beberapa tipe yang paling penting.

Informasi lebih lanjut

tinggi

Jenis Irisan Irisan memungkinkan Anda merujuk pada urutan elemen yang bersebelahan dalam satu koleksi, bukan keseluruhan koleksi.

Potongan adalah sejenis referensi, jadi tidak memiliki kepemilikan.

tinggi
tinggi

Di Rust, irisan adalah tampilan yang mereferensikan rangkaian elemen yang berdekatan dari array atau irisan lainnya. Untuk membuat irisan, Anda perlu menentukan posisi awal dan akhir irisan (tidak termasuk indeks posisi akhir).dalam susunana masuk jika Anda ingin mendapatkannya[2, 3, 4] Untuk potongan ini, Anda harus memulai pada indeks 1 dan mengakhiri pada indeks 4 (tidak termasuk indeks 4).

Berikut cara memperbaiki kode pengujian Anda:

#[test]
fn slice_out_of_array() {
    let a = [12345];

    // 从索引 1 开始,到索引 4 结束的切片
    let nice_slice = &a[1..4];

    assert_eq!([234], nice_slice);
}
  • 1

Dalam contoh ini,&a[1..4] Membuat array daria Irisan dimulai pada indeks 1 dan berakhir pada indeks 3, karena sintaks pemotongan Rust adalah interval kiri-tertutup dan kanan-terbuka (termasuk awal, tetapi bukan akhir).Jadinice_slice Ini berisi arraya tengah[2, 3, 4]

Masukkan jam tangan gemerisik pada baris perintah untuk memulai percobaan loop dalam mengedit kode

tinggi

Memahami Kepemilikan

Kepemilikan adalah fitur Rust yang paling unik dan memiliki implikasi mendalam bagi bahasa lainnya.

Hal ini memungkinkan Rust untuk membuat jaminan keamanan memori tanpa memerlukan pengumpulan sampah

Apa itu Kepemilikan?

tinggi

Aturan Kepemilikan Pertama, mari kita lihat aturan kepemilikan. Ingatlah aturan-aturan ini saat kita membahas contoh-contoh yang mengilustrasikannya:

  • Setiap nilai dalam Rust memiliki pemilik.
  • Hanya dapat ada satu pemilik pada satu waktu.
  • Ketika pemilik keluar dari cakupan, nilainya akan turun

tinggi
tinggi

Contoh kodenya sendiri sudah benar dan menunjukkan konsep kepemilikan dan penyalinan di Rust. Namun, jika Anda ingin memastikan kode Anda dikompilasi dan dijalankan, dan Anda ingin mengatasi beberapa kemungkinan perbaikan atau koreksi, berikut beberapa saran:

  1. memastikan takes_ownership Danmakes_copy berfungsi dimain fungsi yang ditentukan sebelumnya, karena fungsi di Rust perlu dideklarasikan terlebih dahulu baru kemudian digunakan.

  2. menambahkan catatan, jelaskan mengapa s adatakes_ownership tidak dapat digunakan setelah dipanggil, danx adamakes_copy Itu masih dapat digunakan setelah dipanggil.

  3. Tambahkan main tipe pengembalian fungsi, meskipun hal ini tidak diperlukan dalam program sederhana, ini merupakan praktik pemrograman yang baik.

  4. Menggunakan alat pemformatan Rust,Misalnya rustfmt, untuk menjaga kode tetap bersih.

Berikut adalah kode yang dimodifikasi berdasarkan saran di atas:

fn takes_ownership(some_string: String) { // 函数定义在 main 之前
    println!("{}", some_string);
// some_string 的作用域结束,调用 Drop

fn makes_copy(some_integer: i32) { // 函数定义在 main 之前
    println!("{}", some_integer);
// some_integer 的作用域结束,没有调用 Drop,因为 i32 是 Copy 类型

fn main() -> () { // 明确 main 函数的返回类型为 ()
    let s = String::from("hello");  // s 拥有 "hello" 的所有权

    takes_ownership(s);             // s 的值移动到 takes_ownership 函数

    // 下面的代码尝试使用 s 将会导致编译错误,因为 s 的值已经移动
    // let len = s.len(); // 错误:s 已移动

    let x = 5;                      // x 包含值 5

    makes_copy(x);                  // x 的值被复制到 makes_copy 函数
                                    // x 仍然有效,因为 i32 是 Copy 类型

    // x 仍然可以使用
    println!("x is {}", x);
}
  • 1

Dalam versi revisi ini kami telah menambahkan main tipe pengembalian fungsi(),ini berarti main Fungsi ini tidak mengembalikan nilai.Juga, komentar ditambahkan untuk menjelaskan alasannyas adatakes_ownership tidak dapat digunakan setelah dipanggil, danx adamakes_copy Masih berlaku setelah menelepon.Selain itu, kami menunjukkan upaya untuktakes_ownership Gunakan setelah menelepons Contoh yang akan menyebabkan kesalahan kompilasi, danx adamakes_copy Contoh yang masih bisa digunakan setelah menelepon.

Vektor

Vektor adalah salah satu struktur data Rust yang paling banyak digunakan.

Dalam bahasa pemrograman lain, mereka akan disebut Array saja, tetapi karena Rust beroperasi pada level yang sedikit lebih rendah, array dalam Rust disimpan di tumpukan (artinya array tidak dapat bertambah atau berkurang, dan ukurannya perlu diketahui pada waktu kompilasi), dan Vektor disimpan di dalam tumpukan (yang tidak menerapkan batasan ini).

Vektor merupakan topik yang dibahas di bab selanjutnya dalam buku ini, tetapi kami rasa cukup bermanfaat untuk dibahas lebih awal. Kami akan membahas struktur data bermanfaat lainnya, yaitu peta hash, nanti.

Informasi lebih lanjut

tinggi vec_map Fungsinya untuk menerima aVec<i32> ketik (yaitu vektor yang berisi bilangan bulat 32-bit), lalu kembalikan yang baruVec<i32>, setiap elemen dalam vektor baru ini berukuran dua kali ukuran elemen yang bersesuaian dalam vektor asli.

Secara khusus,vec_map dalam fungsimap Dancollect Metode kerjanya seperti ini:

  1. **v.iter()**: Metode ini membuat iterator yang melintasi v setiap elemen vektor.iter Iterator yang dikembalikan oleh metode ini memberikan referensi yang tidak dapat diubah ke elemen dalam vektor.

  2. **.map(|element| { element * 2 })**:map Metode menerima penutupan (fungsi anonim), dalam hal ini penutupan menerima satu parameterelement (referensi yang tidak dapat diubah ke elemen dalam vektor) dan kemudian mengembalikan nilai elemen ini dikalikan 2.Operasi di dalam penutupanelement * 2 Faktanya, Anda melakukan dereferensi data yang ditunjuk oleh referensi (via* operator) dan melakukan operasi perkalian.

  3. **.collect()**:map Metode ini mengembalikan iterator malas yang menerapkan operasi dalam penutupan satu per satu, namun tidak segera mengumpulkan hasilnya.collect metode dipanggil untuk meneruskan inimap Elemen yang telah diproses dikumpulkan menjadi yang baruVec<i32> dalam vektor.

menggunakan map Dancollect Manfaatnya adalah mereka memungkinkan Anda melakukan operasi pada setiap elemen dalam koleksi dengan cara deklaratif dan mengumpulkan hasilnya ke dalam koleksi baru tanpa perlu menulis loop eksplisit. Dengan cara ini kodenya lebih ringkas dan lebih konsisten dengan gaya Rust.

Berikut adalah cara menggunakannya vec_map Contoh fungsi:

fn main() {
    let original_vec = vec![1234];
    let doubled_vec = vec_map(&original_vec);
    println!("{:?}", doubled_vec); // 这将打印:[2, 4, 6, 8]
}
  • 1

Dalam contoh ini,vec_map mengambil alihoriginal_vec referensi, membuat vektor barudoubled_vec, yang berisi dua kali nilai setiap elemen vektor asli dan mencetaknya.

Pindahkan Semantik

Latihan ini diadaptasi dari pnkfelix'S Tutorial Karat -- Terima kasih Felix!!!

Informasi lebih lanjut

Untuk bagian ini, tautan buku sangatlah penting.

pindahkan_semantik1.rs

tinggi

pindahkan_semantik2.rs

tinggi
tinggi

// pindahkan_semantik5.rs

tinggi

Ada aturan untuk referensi yang dapat diubah di Rust: pada waktu tertentu, Anda dapat memiliki sejumlah referensi yang tidak dapat diubah, atau paling banyak satu referensi yang dapat diubah. Aturan ini memastikan keamanan memori dan mencegah data race.

Pada kode yang diberikan, ada masalah:main Fungsi tersebut mencoba membuat dua referensi yang bisa berubahy Danz, keduanya menunjuk ke variabel yang sama x . Hal ini tidak diperbolehkan karena aturan peminjaman Rust tidak mengizinkan beberapa referensi yang bisa diubah ke variabel yang sama dalam cakupan yang sama. Itu sebabnya kodenya tidak dapat dikompilasi.

Untuk memperbaiki masalah ini, Anda perlu memastikan bahwa hanya ada satu referensi yang dapat diubah pada waktu tertentu. Ini kode tetapnya:

fn main() {
    let mut x = 100;
    {
        let y = &mut x;
        *y += 100// 此时 x 的值变为 200
    } // 'y' 的作用域结束,可变引用被销毁
    {
        let z = &mut x; // 可以创建新的可变引用,因为 'y' 已经不存在了
        *z += 1000// 此时 x 的值变为 1200
    } // 'z' 的作用域结束,可变引用被销毁
    assert_eq!(x, 1200); // 断言 x 的值是 1200,这是正确的
}
  • 1

Dalam versi tetap ini, kami memastikan bahwa hanya ada satu referensi yang dapat diubah setiap saat dengan membuat cakupan dalam.Pertama, kami membuaty ruang lingkup, operasi dilakukan padanya, dan kemudian ruang lingkup ini berakhir,y Tidak berlaku lagi.Setelah itu, kami membuatz ruang lingkup, sekali lagi untukx Lakukan operasi. Ini mengikuti aturan peminjaman Rust sehingga kode dikompilasi dan berjalan seperti yang diharapkan.

tinggi
tinggi
tinggi

Pesan kesalahan kompilasi ini menunjukkan masalah siklus hidup dalam kode Rust.Masalahnya adalahstring_uppercase Dalam implementasi fungsinya, ia mencoba untuk menetapkan nilai sementara ke referensi, yang tidak diperbolehkan.

Berikut baris kode yang salah:

data = &data.to_uppercase();
  • 1

Di baris kode ini,data.to_uppercase() Dibuat aString Contoh baru daridata dipinjam.Namun, coba tetapkan referensi ke nilai sementara inidata adalah ilegal karena nilai sementara dimusnahkan segera pada akhir pernyataan, dandata Membutuhkan masa pakai yang lebih lama dibandingkan nilai sementara.

Untuk memperbaiki masalah ini kita perlu memodifikasi string_uppercase Sebuah fungsi yang menerima referensi yang bisa diubah dan memanggilnya langsung pada data yang ditunjuk oleh referensi tersebutmake_uppercase() metode alih-alih mencoba menugaskan kembali. Ini kode tetapnya:

fn string_uppercase(data: &mut String) {
    data.make_uppercase(); // 直接在 data 上调用 make_uppercase 方法

    println!("{}", data);
}
  • 1

Dalam versi tetap ini kami telah menghapusnya mut data: &String tengahmut,Karena data Sudah menjadi referensi yang bisa berubah.Lalu kita langsungdata panggilmake_uppercase(), jadi tidak akan ada masalah dengan nilai sementara.make_uppercase() Metodenya akan diubahdata titik referensi keString contoh tanpa membuat yang baruString

Juga,main Panggilan dalam fungsi juga perlu diperbarui agar dapat memberikan referensi yang bisa diubah:

fn main() {
    let mut data = "Rust is great!".to_string();

    string_uppercase(&mut data); // 传递一个可变引用
    println!("{}", data); // 打印修改后的字符串
}
  • 1

Sekarang,string_uppercase fungsi menerimadata referensi yang bisa berubah, memodifikasinya secara langsung, danmain dalam fungsidata bisa berubah dan bisa sajastring_uppercase diubah. Dengan cara ini kode dikompilasi dan berfungsi seperti yang diharapkan.

tinggi
tinggi
tinggi
/**
【昵称】小王同学
【坐标】山东
【自我介绍】
    1. 高级后端工程师,擅长c++并发编程。
    2. 专注分布式存储,分布式数据库。
    3. 时间的践行者,立志成为一名讲师。
【我的成绩】
    1.  为了走出农村,2次高考
         一次考研失败,
         遇挫之后不知道干什么,开启被动之旅。
    2. 为了找到合适工作,   
        深入研究c++书籍和leetcode 200题目
    3. 为了提高项目能力,参与开源项目建设。
    4. 为了把简单事情说清楚/要干啥
        按照《只管去做》,《福格行为模型>>方法。
        纸上得来终觉浅,绝知此事要躬行
        做一个践行者。
【我能提供】
    1.  后端程序员的简历优化+就业辅导+职业规划
    2.  全栈工程师(c++,rust,go,python )项目开发
    3. 一年践行12本书践行记录。
【希望一起解决什么,开启破圈之旅】
    1. 交接更多朋友,抱团取暖。
        寻找意义本身就更加有意义。
    2. 无法做整个系统,聚焦一个模块
         道可道也,非恒道也 
         名可名也,非恒名也。
         无名 万物之始也
         有名 万物之母也
         别想太多,只管去做,躬身入局
     
链接我: # + v(github):watchpoints   
        #众号:后端开发成长指南
**/
  • 1

Artikel ini ditulis oleh bagus sekaliPenerbitan multi-platform