Teknologian jakaminen

2. päivä Harjoittele Rust-kieltä kahinalla-Move Semanticsilla

2024-07-12

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

Hei kaikki

Tänään suoritin vuoden 2024 autonomisen ajokäyttöjärjestelmän kehittämisen koulutusleirin - Alkeisleirin neljäs vaihe - opetusohjelma

2. päivä Harjoittele Rust-kieltä kahinalla-Move Semanticsilla

alt
alt
alt

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

Kun lähetän koodin, saan viestin, että minulla ei ole lupaa.

alt
alt

Aciton

alt

Viitekehitysympäristön määritys

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

minun aiheeni

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

Luo ssh-avain github-koodin kloonaamiseksi ssh:n kautta. Käytä Linux-ympäristössä ssh-keygen -t rsa -b 4096 -C "postilaatikkosi" -komentoa luodaksesi ssh-avaimen painamalla Enter-näppäintä. Käytä sitten cat ~/.ssh/id_rsa.pub

Primitiiviset tyypit

Rustilla on pari perustyyppiä, jotka on toteutettu suoraan kääntäjään. Tässä osiossa käymme läpi tärkeimmät.

Lisätietoa

alt

Slice Type -osien avulla voit viitata kokoelman peräkkäiseen elementtisarjaan koko kokoelman sijaan.

Viipale on eräänlainen viite, joten sillä ei ole omistusta.

alt
alt

Rustissa slice on näkymä, joka viittaa taulukon tai toisen osion vierekkäisten elementtien sarjaan. Jos haluat luoda viipaleen, sinun on määritettävä viipaleen alku- ja loppupisteet (ei sisällä loppupaikan indeksiä).taulukossaa sisään jos haluat päästä[2, 3, 4] Tätä osuutta varten sinun on aloitettava indeksistä 1 ja päätettävä indeksistä 4 (pois lukien indeksi 4).

Näin voit korjata testikoodisi:

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

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

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

Tässä esimerkissä&a[1..4] Luotiin taulukko kohteestaa Viipaloi alkaa indeksistä 1 ja päättyy indeksiin 3, koska Rustin viipalointisyntaksi on vasemmalle suljettu ja oikealle avoin intervalli (mukaan lukien alku, mutta ei loppu).niinnice_slice Se sisältää taulukona keskellä[2, 3, 4]

Kirjoita rustlings watch komentoriville aloittaaksesi koodin muokkaamisen silmukkakokeilun

alt

Omistajuuden ymmärtäminen

Omistajuus on Rustin ainutlaatuisin ominaisuus, ja sillä on syvällinen vaikutus muuhun kieleen.

Sen avulla Rust voi taata muistin turvallisuuden ilman roskakoria

Mikä on omistus?

alt

Omistussäännöt Katsotaanpa ensin omistussääntöjä. Pidä nämä säännöt mielessä, kun käsittelemme niitä havainnollistavia esimerkkejä:

  • Jokaisella Rustin arvolla on omistaja.
  • Omistajia voi olla vain yksi kerrallaan.
  • Kun omistaja menee ulkopuolelle, arvo pudotetaan

alt
alt

Itse koodinäyte on oikea ja osoittaa omistajuuden ja kopioinnin käsitteet Rustissa. Jos kuitenkin haluat varmistaa, että koodisi käännetään ja suoritetaan, ja haluat tehdä joitain mahdollisia parannuksia tai korjauksia, tässä on joitain ehdotuksia:

  1. Varmista takes_ownership jamakes_copy toimi sisäänmain aiemmin määritelty toiminto, koska Rustin funktiot on ensin ilmoitettava ja vasta sitten käytettävä.

  2. lisää muistiinpanoja, Selitä miksi s olla olemassatakes_ownership ei voi käyttää puhelun jälkeen, jax olla olemassamakes_copy Sitä voidaan edelleen käyttää soittamisen jälkeen.

  3. Lisätä main funktion palautustyyppi, vaikka tämä ei ole välttämätöntä yksinkertaisissa ohjelmissa, se on hyvä ohjelmointikäytäntö.

  4. Rustin muotoilutyökalujen käyttäminen,esimerkiksi rustfmt, jotta koodi pysyy puhtaana.

Tässä on muokattu koodi yllä olevien ehdotusten perusteella:

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

Olemme lisänneet tähän tarkistettuun versioon main funktion palautustyyppi(),Tämä tarkoittaa main Funktio ei palauta arvoa.Lisäksi on lisätty kommentteja, joissa selitetään miksis olla olemassatakes_ownership ei voi käyttää puhelun jälkeen, jax olla olemassamakes_copy Voimassa vielä soiton jälkeen.Lisäksi näytämme yrityksiätakes_ownership Käytä soittamisen jälkeens Esimerkkejä, jotka aiheuttaisivat käännösvirheitä, jax olla olemassamakes_copy Esimerkkejä, joita voidaan edelleen käyttää soittamisen jälkeen.

Vektorit

Vektorit ovat yksi eniten käytetyistä Rust-tietorakenteista.

Muissa ohjelmointikielissä niitä kutsuttaisiin yksinkertaisesti taulukoiksi, mutta koska Rust toimii hieman alemmalla tasolla, rustissa oleva matriisi tallennetaan pinoon (eli se ei voi kasvaa tai kutistua, ja koko on tiedettävä käännösaikana), ja vektori tallennetaan kasaan (missä nämä rajoitukset eivät koske).

Vektorit ovat hieman myöhemmässä luvussa kirjassa, mutta mielestämme ne ovat tarpeeksi hyödyllisiä, jotta niistä voidaan puhua hieman aikaisemmin. Puhumme myöhemmin toisesta hyödyllisestä tietorakenteesta, hash-kartoista.

Lisätietoa

alt vec_map Tehtävä on hyväksyä aVec<i32> tyyppi (eli vektori, joka sisältää 32-bittisen kokonaisluvun), palauttaa sitten uudenVec<i32>, jokainen elementti tässä uudessa vektorissa on kaksi kertaa alkuperäisen vektorin vastaavan elementin koko.

Erityisesti,vec_map toiminnassamap jacollect Menetelmä toimii näin:

  1. **v.iter()**: Tämä menetelmä luo iteraattorin, joka kulkee läpi v jokainen vektorin elementti.iter Menetelmän palauttama iteraattori tarjoaa muuttumattoman viittauksen vektorin elementteihin.

  2. **.map(|element| { element * 2 })**:map Menetelmä hyväksyy sulkemisen (anonyymi funktio), tässä tapauksessa sulkeminen hyväksyy yhden parametrinelement (muuttumaton viittaus vektorin elementtiin) ja palauttaa sitten tämän elementin arvon kerrottuna kahdella.Toiminnot sulkujen sisälläelement * 2 Itse asiassa poistat viittauksen tiedoista, joihin viittaus viittaa (välillä* operaattori) ja suorittaa kertolaskuoperaatioita.

  3. **.collect()**:map Metodi palauttaa laiskan iteraattorin, joka soveltaa sulkemisen toiminnot yksitellen, mutta ei kerää tuloksia heti.collect menetelmää kutsutaan välittämään nämämap Käsitellyt elementit kerätään uuteenVec<i32> vektorissa.

käyttää map jacollect Etuna on, että niiden avulla voit suorittaa operaatioita jokaiselle kokoelman elementille deklaratiivisella tavalla ja kerätä tulokset uuteen kokoelmaan ilman, että sinun tarvitsee kirjoittaa eksplisiittisiä silmukoita. Tällä tavalla koodi on tiiviimpi ja yhtenäisempi Rust-tyylin kanssa.

Tässä on käyttöohjeet vec_map Esimerkki toiminnosta:

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

Tässä esimerkissävec_map vallataoriginal_vec viite, luomalla uuden vektorindoubled_vec, joka sisältää kaksi kertaa alkuperäisen vektorin kunkin elementin arvon ja tulostaa sen.

Siirrä semantiikkaa

Nämä harjoitukset on mukautettu pnkfelix's Ruosteen opetusohjelma -- Kiitos Felix!!!

Lisätietoa

Tässä osiossa kirjalinkit ovat erityisen tärkeitä.

move_semantics1.rs

alt

move_semantics2.rs

alt
alt

// move_semantics5.rs

alt

Rustissa on sääntö muuttuville viittauksille: milloin tahansa sinulla voi olla mikä tahansa määrä muuttumattomia viittauksia tai enintään yksi muuttuva viittaus. Tämä sääntö varmistaa muistin turvallisuuden ja estää datakilpailut.

Annetussa koodissa on ongelma:main Funktio yritti luoda kaksi muuttuvaa viittaustay jaz, molemmat osoittavat samaan muuttujaan x . Tämä ei ole sallittua, koska Rustin lainaussäännöt eivät salli useita muuttuvia viittauksia samaan muuttujaan samassa laajuudessa. Siksi koodia ei käännetä.

Voit korjata tämän ongelman varmistamalla, että kerrallaan on olemassa vain yksi muuttuva viite. Tässä on kiinteä koodi:

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

Tässä kiinteässä versiossa varmistamme, että vain yksi muuttuva viite on olemassa kerrallaan luomalla sisäisen laajuuden.Ensin loimmey laajuus, sille suoritetaan toimenpide, ja sitten tämä alue päättyy,y Ei enään voimassa.Sen jälkeen loimmez soveltamisalaa, taas vartenx Suorita operaatioita. Tämä noudattaa Rustin lainaussääntöjä niin, että koodi käännetään ja suoritetaan odotetulla tavalla.

alt
alt
alt

Tämä käännösvirhesanoma viittaa ruostekoodin elinkaariongelmaan.Ongelmana onstring_uppercase Toiminnon toteutuksessa se yrittää antaa viitteelle väliaikaisen arvon, mikä ei ole sallittua.

Tässä on koodirivi, joka menee pieleen:

data = &data.to_uppercase();
  • 1

Tällä koodirivillädata.to_uppercase() Luotu aString Uusi esimerkkidata lainattu.Yritä kuitenkin määrittää viittaus tälle väliaikaiselle arvolledata on laitonta, koska väliaikainen arvo tuhoutuu välittömästi lausunnon lopussa, jadata Vaatii pidemmän käyttöiän kuin väliaikaiset arvot.

Tämän ongelman korjaamiseksi meidän on muokattava string_uppercase Funktio, joka hyväksyy muuttuvan viittauksen ja kutsuu sitä suoraan dataan, johon viittaus viittaamake_uppercase() menetelmää sen sijaan, että yrität määrittää uudelleen. Tässä on kiinteä koodi:

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

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

Tästä kiinteästä versiosta olemme poistaneet mut data: &String keskellämut,koska data Jo muuttuva viittaus.Sitten me suoraandata soittaamake_uppercase(), joten tilapäisten arvojen kanssa ei ole ongelmia.make_uppercase() Menetelmää muutetaandata viitepisteitäString esimerkiksi luomatta uuttaString

myös,main Toiminnon sisäinen kutsu on myös päivitettävä vastaavasti, jotta se välittää muuttuvan viittauksen:

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

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

Nyt,string_uppercase toiminto hyväksyydata muuttuva viittaus, muokata sitä suoraan jamain toiminnassadata on muuttuva ja voi ollastring_uppercase muokattu. Tällä tavalla koodi käännetään ja toimii odotetulla tavalla.

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

Tämän artikkelin on kirjoittanut mdniceMonialustainen julkaisu