Condivisione della tecnologia

Giorno 2 Fai pratica con il linguaggio Rust con i fruscii-Move Semantics

2024-07-12

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

Ciao a tutti

Oggi ho completato il campo di formazione per lo sviluppo del sistema operativo di guida autonoma 2024 - La quarta fase del campo elementare - Tutorial

Giorno 2 Fai pratica con il linguaggio Rust con i fruscii-Move Semantics

altrorororororororororororororororororororororororo
altrorororororororororororororororororororororororo
altrorororororororororororororororororororororororo

https://doc.rust-lang.org/stable/book/ch04-00-understanding-ownership.html

Quando invio il codice, ricevo un messaggio che non ho l'autorizzazione. Come posso uscire?

altrorororororororororororororororororororororororo
altrorororororororororororororororororororororororo

acitone

altrorororororororororororororororororororororororo

Configurazione dell'ambiente di sviluppo di riferimento

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

mio argomento

https://github.com/cicvedu/rustlings-semester-4-watchpoints

Crea una chiave ssh per clonare il codice github tramite ssh. Nell'ambiente Linux, utilizza il comando ssh-keygen -t rsa -b 4096 -C "la tua casella di posta" per creare una chiave ssh. Basta premere Invio per tutte le seguenti opzioni. Quindi usa cat ~/.ssh/id_rsa.pub

Tipi primitivi

Rust ha un paio di tipi base che sono implementati direttamente nel compilatore. In questa sezione, esamineremo quelli più importanti.

Ulteriori informazioni

altrorororororororororororororororororororororororo

Tipo Slice Le Slice consentono di fare riferimento a una sequenza contigua di elementi in una raccolta anziché all'intera raccolta.

Una fetta è una sorta di riferimento, quindi non ha proprietà.

altrorororororororororororororororororororororororo
altrorororororororororororororororororororororororo

In Rust, una porzione è una vista che fa riferimento a una sequenza di elementi contigui da un array o da un'altra porzione. Per creare una sezione, è necessario specificare le posizioni iniziale e finale della sezione (escluso l'indice della posizione finale).nella matricea dentro se vuoi ottenere[2, 3, 4] Per questa sezione è necessario iniziare dall'indice 1 e terminare con l'indice 4 (escluso l'indice 4).

Ecco come correggere il codice di test:

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

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

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

In questo esempio,&a[1..4] Creato un array daa Lo slice inizia all'indice 1 e termina all'indice 3, perché la sintassi dello slicing di Rust è un intervallo chiuso a sinistra e aperto a destra (incluso l'inizio, ma non la fine).COSÌnice_slice Contiene l'arraya mezzo[2, 3, 4]

Inserisci fruscii guarda sulla riga di comando per avviare l'esperimento del ciclo di modifica del codice

altrorororororororororororororororororororororororo

Comprendere la proprietà

La proprietà è la caratteristica più esclusiva di Rust e ha profonde implicazioni per il resto del linguaggio.

Permette a Rust di creare garanzie di sicurezza della memoria senza bisogno di un garbage collector

Che cosa è la proprietà?

altrorororororororororororororororororororororororo

Regole di proprietà Innanzitutto, diamo un'occhiata alle regole di proprietà. Tieni a mente queste regole mentre esaminiamo gli esempi che le illustrano:

  • Ogni valore in Rust ha un proprietario.
  • Può esserci un solo proprietario alla volta.
  • Quando il proprietario esce dall'ambito, il valore verrà eliminato

altrorororororororororororororororororororororororo
altrorororororororororororororororororororororororo

L'esempio di codice stesso è corretto e dimostra i concetti di proprietà e copia in Rust. Tuttavia, se vuoi assicurarti che il tuo codice venga compilato ed eseguito e desideri apportare alcuni possibili miglioramenti o correzioni, ecco alcuni suggerimenti:

  1. assicurarsi takes_ownership Emakes_copy funzione dentromain funzione definita prima, perché le funzioni in Rust devono essere prima dichiarate e poi utilizzate.

  2. aggiungere note, spiega perchè s esisteretakes_ownership non può essere utilizzato dopo essere stato chiamato, ex esisteremakes_copy Può ancora essere utilizzato dopo essere stato chiamato.

  3. aggiungere a main tipo di restituzione della funzione, sebbene ciò non sia necessario nei programmi semplici, è una buona pratica di programmazione.

  4. Utilizzando gli strumenti di formattazione di Rust,Per esempio rustfmt, per mantenere il codice pulito.

Ecco il codice modificato in base ai suggerimenti di cui sopra:

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

In questa versione rivista abbiamo aggiunto main tipo di restituzione della funzione(),questo significa main La funzione non restituisce alcun valore.Inoltre, vengono aggiunti commenti per spiegare il motivos esisteretakes_ownership non può essere utilizzato dopo essere stato chiamato, ex esisteremakes_copy Ancora valido dopo la chiamata.Inoltre, mostriamo i tentativi di farlotakes_ownership Utilizzare dopo aver chiamatos Esempi che potrebbero causare errori di compilazione ex esisteremakes_copy Esempi che possono ancora essere utilizzati dopo la chiamata.

Vettori

I vettori sono una delle strutture dati Rust più utilizzate.

In altri linguaggi di programmazione verrebbero semplicemente chiamati Array, ma poiché Rust opera a un livello leggermente inferiore, un array in Rust viene memorizzato sullo stack (il che significa che non può aumentare o diminuire e la dimensione deve essere nota in fase di compilazione), mentre un Vector viene memorizzato nell'heap (dove queste restrizioni non si applicano).

I vettori sono un capitolo un po' più avanti nel libro, ma pensiamo che siano abbastanza utili da parlarne un po' prima. Parleremo più avanti dell'altra struttura dati utile, le mappe hash.

Ulteriori informazioni

altrorororororororororororororororororororororororo vec_map La funzione è accettare aVec<i32> type (ovvero un vettore contenente un intero a 32 bit), quindi restituisce un newVec<i32>, ogni elemento di questo nuovo vettore ha una dimensione doppia rispetto all'elemento corrispondente nel vettore originale.

Nello specifico,vec_map in funzionemap Ecollect Il metodo funziona in questo modo:

  1. **v.iter()**: questo metodo crea un iteratore che attraversa v ciascun elemento del vettore.iter L'iteratore restituito dal metodo fornisce un riferimento immutabile agli elementi nel vettore.

  2. **.map(|element| { element * 2 })**:map Il metodo accetta una chiusura (funzione anonima), in questo caso la chiusura accetta un parametroelement (un riferimento immutabile a un elemento nel vettore) e quindi restituisce il valore di questo elemento moltiplicato per 2.Operazioni all'interno delle chiusureelement * 2 In effetti, stai dereferenziando i dati indicati dal riferimento (via* operatore) ed eseguire operazioni di moltiplicazione.

  3. **.collect()**:map Il metodo restituisce un iteratore pigro che applica le operazioni nella chiusura una per una, ma non raccoglie immediatamente i risultati.collect viene chiamato il metodo per passarlimap Gli elementi elaborati vengono raccolti in un nuovoVec<i32> nel vettore.

utilizzo map Ecollect Il vantaggio è che consentono di eseguire operazioni su ciascun elemento della raccolta in modo dichiarativo e di raccogliere i risultati in una nuova raccolta senza la necessità di scrivere cicli espliciti. In questo modo il codice risulta più conciso e più coerente con lo stile Rust.

Ecco come utilizzare vec_map Esempio di funzione:

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

In questo esempio,vec_map rilevareoriginal_vec riferimento, creando un nuovo vettoredoubled_vec, che contiene il doppio del valore di ciascun elemento del vettore originale e lo stampa.

Spostare la semantica

Questi esercizi sono adattati da Pnkfelix'S Tutorial sulla ruggine -- Grazie Felix!!!

Ulteriori informazioni

In questa sezione i link ai libri sono particolarmente importanti.

sposta_semantica1.rs

altrorororororororororororororororororororororororo

sposta_semantica2.rs

altrorororororororororororororororororororororororo
altrorororororororororororororororororororororororo

// sposta_semantics5.rs

altrorororororororororororororororororororororororo

Esiste una regola per i riferimenti mutabili in Rust: in qualsiasi momento, puoi avere un numero qualsiasi di riferimenti immutabili, o al massimo un riferimento mutabile. Questa regola garantisce la sicurezza della memoria e previene le gare di dati.

Nel codice fornito c'è un problema:main La funzione ha tentato di creare due riferimenti modificabiliy Ez, entrambi puntano alla stessa variabile x . Ciò non è consentito perché le regole di prestito di Rust non consentono più riferimenti mutabili alla stessa variabile nello stesso ambito. Ecco perché il codice non viene compilato.

Per risolvere questo problema, è necessario assicurarsi che esista un solo riferimento modificabile alla volta. Ecco il codice fisso:

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

In questa versione fissa, ci assicuriamo che esista un solo riferimento mutabile alla volta creando un ambito interno.Innanzitutto, abbiamo creatoy ambito, viene eseguita un'operazione su di esso e quindi questo ambito termina,y Non più valido.Successivamente, abbiamo creatoz ambito, ancora una volta perx Eseguire le operazioni. Questo segue le regole di prestito di Rust in modo che il codice venga compilato e eseguito come previsto.

altrorororororororororororororororororororororororo
altrorororororororororororororororororororororororo
altrorororororororororororororororororororororororo

Questo messaggio di errore di compilazione indica un problema del ciclo di vita nel codice Rust.Il problema èstring_uppercase Nell'implementazione della funzione si tenta di assegnare un valore temporaneo ad un riferimento, cosa non consentita.

Ecco la riga di codice che va storta:

data = &data.to_uppercase();
  • 1

In questa riga di codice,data.to_uppercase() Creato unString Una nuova istanza didata preso in prestito.Tuttavia, prova ad assegnare un riferimento a questo valore temporaneo adata è illegale perché il valore temporaneo viene distrutto immediatamente alla fine dell'istruzione, edata Richiede una durata più lunga rispetto ai valori temporanei.

Per risolvere questo problema dobbiamo modificare string_uppercase Una funzione che accetta un riferimento mutabile e lo chiama direttamente sui dati a cui punta quel riferimentomake_uppercase() metodo invece di provare a riassegnare. Ecco il codice fisso:

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

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

In questa versione fissa abbiamo rimosso mut data: &String mezzomut,Perché data Già un riferimento mutevole.Allora noi direttamentedata rivolgersimake_uppercase(), quindi non ci saranno problemi con i valori temporanei.make_uppercase() Il metodo verrà modificatodata punti di riferimento aString istanza senza crearne una nuovaString

Anche,main Anche la chiamata all'interno della funzione deve essere aggiornata di conseguenza per passare un riferimento mutabile:

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

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

Ora,string_uppercase la funzione accettadata un riferimento mutabile, modificarlo direttamente emain in funzionedata è mutevole e può esserlostring_uppercase modificata. In questo modo il codice viene compilato e funziona come previsto.

altrorororororororororororororororororororororororo
altrorororororororororororororororororororororororo
altrorororororororororororororororororororororororo
/**
【昵称】小王同学
【坐标】山东
【自我介绍】
    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

Questo articolo è scritto da MdNizzaPubblicazione multipiattaforma