Taxmin qilish o'yinini dasturlash

Keling, birgalikda amaliy loyiha orqali Rustga o'taylik! Ushbu bob sizni bir nechta umumiy Rust tushunchalari bilan tanishtirib, ulardan haqiqiy dasturda qanday foydalanishni ko'rsatib beradi. Siz let, match, metodlari, bog'langan funksiyalar, external cratelardan foydalanish va boshqalar haqida bilib olasiz! Keyingi boblarda biz ushbu fikrlarni batafsilroq ko'rib chiqamiz. Ushbu bobda siz faqat asoslarni mashq qilasiz.

Biz klassik boshlang'ich dasturlash muammosini amalga oshiramiz: taxmin qilish o'yini. Bu qanday ishlaydi: dastur 1 dan 100 gacha tasodifiy butun son hosil qiladi. Keyin u o'yinchini taxmin qilishni taklif qiladi.Tahmin kiritilgandan so'ng, dastur taxmin kichik yoki katta ekanligini ko'rsatadi. Agar taxmin to'g'ri bo'lsa, o'yin tabrik xabarini chop etadi va chiqadi.

Yangi loyiha yaratish

Yangi loyihani o'rnatish uchun 1-bobda yaratgan projects jildiga o'ting va Cargo-dan foydalanib yangi loyiha yarating, masalan:

$ cargo new taxminiy_raqam
$ cd taxminiy_raqam

Birinchi cargo new buyrug'i birinchi argument sifatida loyiha nomini (taxminiy_raqam)ni oladi. Ikkinchi buyruq yangi loyiha jildiga kiradi.

Yaratilgan Cargo.toml fayliga qarang:

Fayl nomi: Cargo.toml

[package]
name = "taxminiy_raqam"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

1-bobda ko'rganingizdek, cargo new siz uchun “Hello, world!” so'zini chop etadigan dastur yaratadi. src/main.rs faylini tekshiring:

Fayl nomi: src/main.rs

fn main() {
    println!("Hello, world!");
}

Keling, ushbu "Hello, world!" dasturni yarating va cargo run buyrug'i yordamida ishga tushiring :

$ cargo run
   Compiling taxminiy_raqam v0.1.0 (file:///projects/taxminiy_raqam)
    Finished dev [unoptimized + debuginfo] target(s) in 1.50s
     Running `target/debug/taxminiy_raqam`
Hello, world!

run buyrug‘i loyihani tezda takrorlash kerak bo‘lganda foydali bo‘ladi, biz bu o‘yinda qilganimizdek, keyingisiga o‘tishdan oldin har bir iteratsiyani tezda sinab ko‘ramiz.

src/main.rs faylini qayta oching. Siz ushbu fayldagi barcha kodlarni yozasiz.

Taxmin qilish o'yiniga ishlov berish

Taxmin qilish o'yini dasturining birinchi qismi foydalanuvchi kiritishini so'raydi, ushbu kiritishni qayta ishlaydi va kirish kutilgan shaklda ekanligini tekshiradi. Boshlash uchun biz o'yinchiga taxmin kiritishga ruxsat beramiz. 2-1 ro'yxatdagi kodni src/main.rs ichiga kiriting.

Fayl nomi: src/main.rs

use std::io;

fn main() {
    println!("Raqamni topish o'yini!");

    println!("Iltimos, taxminingizni kiriting.");

    let mut taxmin = String::new();

    io::stdin()
        .read_line(&mut taxmin)
        .expect("Satrni o‘qib bo‘lmadi");

    println!("Sizning taxminingiz: {taxmin}");
}

Ro'yxat 2-1: Foydalanuvchi tomonidan taxmin qilinadigan va uni chop etadigan kod

Ushbu kod juda ko'p ma'lumotlarni o'z ichiga oladi, shuning uchun uni satrga o'tkazamiz. Foydalanuvchi kiritishini olish va natijani chiqish sifatida chop etish uchun biz io input/output kutubxonasini qamrab olishimiz kerak. io kutubxonasi std deb nomlanuvchi standart kutubxonadan keladi:

use std::io;

Odatda, Rust standart kutubxonada belgilangan elementlar to'plamiga ega bo'lib, u har bir dastur doirasiga kiradi. Ushbu to'plam prelude deb ataladi va siz undagi hamma narsani standart kutubxona texnik hujjatlarida ko'rishingiz mumkin.

Agar siz foydalanmoqchi bo'lgan tur preludeda bo'lmasa, siz ushbu turni use iborasi bilan aniq kiritishingiz kerak. std::io kutubxonasidan foydalanish sizga bir qator foydali xususiyatlarni, jumladan, foydalanuvchi kiritishini qabul qilish imkoniyatini beradi.

1-bobda ko'rganingizdek, main funksiya dasturga kirish nuqtasidir:

use std::io;

fn main() {
    println!("Raqamni topish o'yini!");

    println!("Iltimos, taxminingizni kiriting.");

    let mut taxmin = String::new();

    io::stdin()
        .read_line(&mut taxmin)
        .expect("Satrni o‘qib bo‘lmadi");

    println!("Sizning taxminingiz: {taxmin}");
}

fn sintaksisi yangi funktsiyani e'lon qiladi; Qavslar, (), hech qanday parametr yo'qligini bildiradi; va jingalak qavs, {, funksiyaning asosiy qismini boshlaydi.

1-bobda ham bilib olganingizdek, println! bu ekranga satrni chop etuvchi makros:

use std::io;

fn main() {
    println!("Raqamni topish o'yini!");

    println!("Iltimos, taxminingizni kiriting.");

    let mut taxmin = String::new();

    io::stdin()
        .read_line(&mut taxmin)
        .expect("Satrni o‘qib bo‘lmadi");

    println!("Sizning taxminingiz: {taxmin}");
}

Ushbu kod o'yin nima ekanligini ko'rsatuvchi va foydalanuvchidan ma'lumot so'rashni chop etadi.

O'zgaruvchilar bilan qiymatlarni saqlash

Keyinchalik, foydalanuvchi ma'lumotlarini saqlash uchun o'zgaruvchi yaratamiz, masalan:

use std::io;

fn main() {
    println!("Raqamni topish o'yini!");

    println!("Iltimos, taxminingizni kiriting.");

    let mut taxmin = String::new();

    io::stdin()
        .read_line(&mut taxmin)
        .expect("Satrni o‘qib bo‘lmadi");

    println!("Sizning taxminingiz: {taxmin}");
}

Endi dastur qiziqarli bo'lib bormoqda! Bu kichik satrda juda ko'p narsa bor. O'zgaruvchini yaratish uchun let iborasidan foydalanamiz. Mana yana bir misol:

let olmalar = 5;

Bu qator olmalar nomli yangi o‘zgaruvchini yaratadi va uni 5 qiymatiga bog‘laydi. Rustda o'zgaruvchilar standard bo'yicha o'zgarmasdir, ya'ni o'zgaruvchiga qiymat berganimizdan keyin qiymat o'zgarmaydi.Biz ushbu kontseptsiyani 3-bobdagi ”O'zgaruvchilar va O'zgaruvchanlik” bo'limida batafsil muhokama qilamiz. Oʻzgaruvchini oʻzgaruvchan qilish uchun oʻzgaruvchi nomidan oldin mut qoʻshamiz:

let olmalar = 5; // o'zgarmas
let mut bananlar = 5; // o'zgaruvchan

Eslatma: // sintaksisi satr oxirigacha davom etadigan izohni boshlaydi. Rust izohlarda hamma narsani e'tiborsiz qoldiradi. Izohlarni 3-bobda batafsilroq muhokama qilamiz.

Taxmin qilish o'yin dasturiga qaytsak, endi bilasizki, let mut taxmin taxmin nomli o'zgaruvchan o'zgaruvchini kiritadi. Teng belgisi (=) Rustga biz hozir biror narsani oʻzgaruvchiga bogʻlamoqchi ekanligimizni bildiradi. Tenglik belgisining o'ng tomonida taxmin bog'langan qiymat joylashgan bo'lib, u String::new funksiyasini chaqirish natijasidir, bu Stringning yangi nusxasini qaytaradi. String standart kutubxona tomonidan taqdim etilgan string turi bo'lib, u rivojlantirib boriladigan, UTF-8 kodlangan matn bitidir.

::new qatoridagi :: sintaksisi new String tipidagi bog'langan funksiya ekanligini bildiradi. Assosiatsiyalangan funksiya bu funksiya turida amalga oshiriladi, bu holda String. Ushbu new funksiya yangi, bo'sh qatorni yaratadi. Siz ko'p turdagi new funksiyani topasiz, chunki u qandaydir yangi qiymatni yaratadigan funksiyaning umumiy nomi.

To'liq let mut taxmin = String::new(); qatori hozirda String ning yangi, bo'sh nusxasiga bog'langan o'zgaruvchan o'zgaruvchini yaratadi.

Foydalanuvchi ma'lumotlarini qabul qilish

Eslatib o'tamiz, biz dasturning birinchi qatoriga use std::io; bilan standart kutubxonadan input/output funksiyasini kiritgan edik. Endi biz io modulidan stdin funksiyasini chaqiramiz, bu bizga foydalanuvchi kiritishini boshqarish imkonini beradi:

use std::io;

fn main() {
    println!("Raqamni topish o'yini!");

    println!("Iltimos, taxminingizni kiriting.");

    let mut taxmin = String::new();

    io::stdin()
        .read_line(&mut taxmin)
        .expect("Satrni o‘qib bo‘lmadi");

    println!("Sizning taxminingiz: {taxmin}");
}

Agar biz dasturning boshida use std::io; bilan io kutubxonasini import qilmagan bo'lsak, biz ushbu funktsiya chaqiruvini std::io::stdin sifatida yozish orqali funksiyadan foydalanishimiz xam mumkin. stdin funksiyasi std::io::Stdin misolini qaytaradi, bu sizning terminalingiz uchun standart kirish uchun asosni ifodalovchi tur.

Keyinchalik, .read_line(&mut taxmin) qatori foydalanuvchidan ma'lumot olish uchun standart kiritish nuqtasidagi read_line metodini chaqiradi. Shuningdek, foydalanuvchi kiritgan maʼlumotlarni qaysi qatorda saqlash kerakligini aytish uchun read_line ga argument sifatida &mut taxmin ni oʻtkazamiz. read_line ning toʻliq vazifasi foydalanuvchi nima yozganidan qatʼiy nazar standart kiritishga olish va uni satrga qoʻshishdir (uning mazmunini qayta yozmasdan), shuning uchun biz bu qatorni argument sifatida beramiz. String argumenti o'zgaruvchan bo'lishi kerak, shuning uchun metod string tarkibini o'zgartirishi mumkin.

& bu argument reference(havola) ekanligini bildiradi, bu sizga kodingizning bir nechta qismlariga ushbu ma'lumotni xotiraga bir necha marta nusxalash kerak bo'lmasdan bitta ma'lumotga kirish imkonini beradi. Referencelar murakkab xususiyat bo'lib, Rustning asosiy afzalliklaridan biri havolalardan foydalanish qanchalik xavfsiz va oson ekanligidir. Ushbu dasturni tugatish uchun ko'p bilimlrga ega bo'lishingiz shart emas. Hozircha siz bilishingiz kerak bo'lgan narsa shundaki, o'zgaruvchilar singari, havolalar ham standard bo'yicha o'zgarmasdir. Demak, uni oʻzgaruvchan qilish uchun &taxmin oʻrniga &mut taxmin yozish kerak. (4-bobda havolalar ko'proq va yaxshiroq tushuntiriladi)

Potensial nosozlikni Result turi bilan hal qilish

Biz hali ham ushbu kod qatori ustida ishlayapmiz. Biz hozir matnning uchinchi qatorini muhokama qilmoqdamiz, lekin u hali ham bitta mantiqiy kod qatorining bir qismi ekanligini unutmang. Keyingi qism bu metod:

use std::io;

fn main() {
    println!("Raqamni topish o'yini!");

    println!("Iltimos, taxminingizni kiriting.");

    let mut taxmin = String::new();

    io::stdin()
        .read_line(&mut taxmin)
        .expect("Satrni o‘qib bo‘lmadi");

    println!("Sizning taxminingiz: {taxmin}");
}

Biz ushbu kodni quyidagicha yozishimiz mumkin edi:

io::stdin().read_line(&mut taxmin).expect("Satrni o‘qib bo‘lmadi");

Biroq, bitta uzun qatorni o'qish qiyin, shuning uchun uni bo'lish yaxshidir. .method_name() sintaksisi bilan metodni chaqirganda uzun qatorlarni ajratishga yordam berish uchun yangi qator va boshqa bo'shliqlarni kiritish ko'pincha oqilona. Endi bu kod nima qilishini muhokama qilaylik.

Yuqorida aytib o'tilganidek, read_line foydalanuvchi kiritgan narsani biz unga o'tkazadigan qatorga qo'yadi, lekin u Result qiymatini ham qaytaradi. Result - ko'pincha enum deb ataladigan enumeration, bu bir nechta mumkin bo'lgan holatlardan birida bo'lishi mumkin bo'lgan tur. Har bir mumkin bo'lgan holatni variant deb ataymiz.

6-bobda enumlar batafsilroq yoritiladi. Ushbu Result turlarining maqsadi xatolarni qayta ishlash ma'lumotlarini kodlashdir.

Result variantlari Ok va Err. Ok varianti operatsiya muvaffaqiyatli bo'lganligini bildiradi va Ok ichida muvaffaqiyatli yaratilgan qiymat. Err varianti operatsiya bajarilmaganligini bildiradi va Err operatsiya qanday yoki nima uchun bajarilmagani haqida maʼlumotni oʻz ichiga oladi.

Result turidagi qiymatlar, har qanday turdagi qiymatlar kabi, ularda aniqlangan metodlarga ega. Result misolida siz murojat qilishingiz mumkin bo'lgan expect metodi mavjud. Agar Result ning ushbu namunasi Err qiymati bo'lsa, expect dasturning ishlamay qolishiga olib keladi va expect ga argument sifatida siz uzatgan xabarni ko'rsatadi. Agar read_line metodi Errni qaytarsa, bu asosiy operatsion tizimdan kelgan xato natijasi bo'lishi mumkin.

Agar Resultning ushbu namunasi Ok qiymati bo‘lsa, expect Ok ushlab turgan qaytarish qiymatini oladi va siz undan foydalanishingiz uchun aynan shu qiymatni sizga qaytaradi. Bunday holda, bu qiymat foydalanuvchi kiritishidagi baytlar soni.

Agar siz expect ga murojat qilmasangiz, dastur kompilyatsiya qilinadi, lekin siz ogohlantirish olasiz:

$ cargo build
   Compiling taxminiy_raqam v0.1.0 (file:///projects/taxminiy_raqam)
warning: unused `Result` that must be used
  --> src/main.rs:10:5
   |
10 |     io::stdin().read_line(&mut taxmin);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: this `Result` may be an `Err` variant, which should be handled
   = note: `#[warn(unused_must_use)]` on by default

warning: `taxminiy_raqam` (bin "taxminiy_raqam") generated 1 warning
    Finished dev [unoptimized + debuginfo] target(s) in 0.59s

Rust read_line dan qaytarilgan Result qiymatini ishlatmaganligingiz haqida ogohlantiradi, bu dastur mumkin bo'lgan xatoni hal qilmaganligini ko'rsatadi.

Ogohlantirishni yo'qotishning to'g'ri yo'li aslida xatolarni qayta ishlash kodini yozishdir, ammo bizning holatlarimizda muammo yuzaga kelganda biz ushbu dasturni ishdan chiqarishni xohlaymiz, shuning uchun biz expect dan foydalanishimiz mumkin. Xatolarni tiklash haqida [9-bobda]recover] bilib olasiz.

Qiymatlarni println! bilan chop etish

Yopuvchi jingalak qavsdan tashqari, kodda hozirgacha muhokama qilinadigan yana bitta satr mavjud:

use std::io;

fn main() {
    println!("Raqamni topish o'yini!");

    println!("Iltimos, taxminingizni kiriting.");

    let mut taxmin = String::new();

    io::stdin()
        .read_line(&mut taxmin)
        .expect("Satrni o‘qib bo‘lmadi");

    println!("Sizning taxminingiz: {taxmin}");
}

Ushbu satr foydalanuvchi kiritishini o'z ichiga olgan qatorni chop etadi. {} jingalak qavslar to'plami o'rnini egallaydi: {} qiymatini joyida ushlab turadigan qisqichbaqa qisqichlari deb tasavvur qiling. O'zgaruvchining qiymatini chop etishda o'zgaruvchi nomi jingalak qavslar ichiga kirishi mumkin. Ifodani baholash natijasini chop etishda format satriga bo'sh jingalak qavslarni joylashtiring, so'ngra har bir bo'sh jingalak qavs o'rnini egallagan holda bir xil tartibda chop etish uchun vergul bilan ajratilgan iboralar ro'yxati bilan format qatoriga amal qiling. O‘zgaruvchini va ifoda natijasini println! ga bitta chaqiruvda chop etish quyidagicha ko‘rinadi:

#![allow(unused)]
fn main() {
let x = 5;
let y = 10;

println!("x = {x} va y + 2 = {}", y + 2);
}

Bu kod x = 5 va y + 2 = 12 ni chop etadi.

Birinchi qismni sinovdan o'tkazish

Keling, taxmin qilish o'yinining birinchi qismini sinab ko'raylik. Uni cargo run yordamida ishga tushiring:

$ cargo run
   Compiling taxminiy_raqam v0.1.0 (file:///projects/taxminiy_raqam)
    Finished dev [unoptimized + debuginfo] target(s) in 6.44s
     Running `target/debug/taxminiy_raqam`
Raqamni topish o'yini!
Iltimos, taxminingizni kiriting.
6
Sizni taxminingiz: 6

Shu nuqtada, o'yinning birinchi qismi tugadi: biz klaviaturadan ma'lumotlarni olamiz va keyin uni chop etamiz.

Yashirin raqam yaratish

Keyinchalik, foydalanuvchi taxmin qilishga harakat qiladigan maxfiy raqamni yaratishimiz kerak. Yashirin raqam har safar boshqacha bo'lishi kerak, shuning uchun o'yinni bir necha marta o'ynash qiziqarli bo'ladi. O'yin juda qiyin bo'lmasligi uchun biz 1 dan 100 gacha bo'lgan tasodifiy raqamdan foydalanamiz. Rust hali o'zining standart kutubxonasida tasodifiy raqamlar funksiyasini o'z ichiga olmaydi. Biroq, Rust jamoasi ushbu funksiyaga rand cratei taqdim etadi.

Ko'proq funksionallikka ega bo'lish uchun Cratedan foydalanish

Esda tutingki, crate Rust manba kodi fayllari to'plamidir. Biz qurayotgan loyiha binary crate bo'lib, u bajariladigan. rand crate boshqa dasturlarda foydalanish uchun moʻljallangan va mustaqil ravishda bajarib boʻlmaydigan kodni oʻz ichiga olgan library crate.

Cargoning tashqi cratelarni muvofiqlashtirishi bu erda Cargp haqiqatan ham ishlaydi. rand dan foydalanadigan kodni yozishdan oldin, biz Cargo.toml faylini rand cratesini dependency sifatida qo‘shish uchun o‘zgartirishimiz kerak. Hozir o‘sha faylni oching va Cargo siz uchun yaratgan[dependencies] bo‘limi sarlavhasi ostiga quyidagi qatorni qo‘shing.rand ni aynan bizda boʻlganidek, ushbu versiya raqami bilan belgilaganingizga ishonch hosil qiling, aks holda ushbu qoʻllanmadagi kod misollari ishlamasligi mumkin:

Fayl nomi: Cargo.toml

[dependencies]
rand = "0.8.5"

Cargo.toml faylida sarlavhadan keyingi hamma narsa boshqa bo'lim boshlanmaguncha davom etadigan bo'limning bir qismidir. [dependencies] da siz Cargo loyihangiz qaysi tashqi cratelarga bog'liqligini va bu cratelarning qaysi versiyalari kerakligini aytasiz. Bunday holda, biz rand crateni 0.8.5 semantik versiya spetsifikatsiyasi bilan belgilaymiz. Cargo versiya raqamlarini yozish uchun standart bo'lgan Semantic Versioningni (ba'zan SemVer deb ataladi) tushunadi. 0.8.5 spetsifikatsiyasi aslida ^0.8.5 ning qisqartmasi boʻlib, kamida 0.8.5, lekin 0.9.0 dan past boʻlgan har qanday versiyani bildiradi.

Cargo ushbu versiyalarni 0.8.5 versiyasiga mos keladigan umumiy API-larga ega deb hisoblaydi va bu spetsifikatsiya sizga ushbu bobdagi kod bilan tuziladigan so‘nggi patch versiyasini olishingizni kafolatlaydi. 0.9.0 yoki undan kattaroq versiyalar quyidagi misollar ishlatadigan API bilan bir xil bo'lishi kafolatlanmaydi.

Endi, hech qanday kodni o'zgartirmasdan, 2-2 ro'yxatda ko'rsatilganidek, loyihani build qilaylik.

$ cargo build
    Updating crates.io index
  Downloaded rand v0.8.5
  Downloaded libc v0.2.127
  Downloaded getrandom v0.2.7
  Downloaded cfg-if v1.0.0
  Downloaded ppv-lite86 v0.2.16
  Downloaded rand_chacha v0.3.1
  Downloaded rand_core v0.6.3
   Compiling libc v0.2.127
   Compiling getrandom v0.2.7
   Compiling cfg-if v1.0.0
   Compiling ppv-lite86 v0.2.16
   Compiling rand_core v0.6.3
   Compiling rand_chacha v0.3.1
   Compiling rand v0.8.5
   Compiling taxminiy_raqam v0.1.0 (file:///projects/taxminiy_raqam)
    Finished dev [unoptimized + debuginfo] target(s) in 2.53s

Ro'yxat 2-2: rand cratesini dependency sifatida qo'shgandan so'ng cargo build dan olingan natija

Siz turli xil versiya raqamlarini (lekin ularning barchasi SemVer tufayli kod bilan mos keladi!) va turli xil satrlarni (operatsion tizimga qarab) ko'rishingiz mumkin va satrlar boshqa tartibda bo'lishi mumkin.

Biz tashqi dependency qo'shganimizda, Cargo Crates.io ma'lumotlarining nusxasi bo'lgan registry dan dependency uchun zarur bo'lgan barcha narsalarning so'nggi versiyalarini oladi.Crates.io - bu Rust ekotizimidagi odamlar o'zlarining ochiq manbali Rust loyihalarini boshqalar foydalanishi uchun joylashtiradigan joy.

registrni yangilagandan so'ng, Cargo [dependencies] bo'limini tekshiradi va ro'yxatda hali yuklab olinmagan cratelarni yuklab oladi. Bu holatda, garchi biz faqat rand ni dependency sifatida ko'rsatgan bo'lsak-da, Cargo rand ishlashga bog'liq bo'lgan boshqa cratelarni ham oldi. Cratelarni yuklab olgandan so'ng, Rust ularni kompilyatsiya qiladi va keyin mavjud bo'lgan dependency bilan loyihani tuzadi.

Agar siz hech qanday o'zgartirishlarsiz darhol cargo build ni qayta ishga tushirsangiz, Finished qatoridan boshqa hech qanday natija olmaysiz. Cargo allaqachon dependencylarni yuklab olganini va kompilyatsiya qilganini biladi va siz Cargo.toml faylida ular haqida hech narsani o'zgartirmagansiz. Cargo, shuningdek, kodingiz haqida hech narsani o'zgartirmaganligingizni biladi, shuning uchun u ham uni qayta kompilyatsiya qilmaydi. Hech narsa qilmasdan, u shunchaki chiqib ketadi.

Agar siz src/main.rs faylini ochsangiz, ahamiyatsiz o'zgarishlarni amalga oshirsangiz va keyin uni saqlab va qayta build qilsangiz, siz faqat ikkita chiqish qatorini ko'rasiz:

$ cargo build
   Compiling taxminiy_raqam v0.1.0 (file:///projects/taxminiy_raqam)
    Finished dev [unoptimized + debuginfo] target(s) in 2.53 secs

Bu satrlar shuni ko'rsatadiki, Cargo faqat src/main.rs fayliga kichik o'zgartirishingiz bilan buildni yangilaydi. Sizning dependencylaringiz o'zgarmadi, shuning uchun Cargo allaqachon yuklab olingan va ular uchun tuzilgan narsadan qayta foydalanishi mumkinligini biladi..

Cargo.lock fayli bilan qayta tiklanadigan tuzilmalarni ta'minlash

Cargoda siz yoki boshqa birov kodingizni har safar yaratganingizda bir xil artefaktni qayta tiklashingiz mumkinligini ta'minlaydigan mexanizm mavjud: Siz aksini ko'rsatmaguningizcha, cargo faqat siz ko'rsatgan dependency versiyalaridan foydalanadi. Masalan, kelasi hafta rand cratening 0.8.6 versiyasi chiqadi va bu versiyada muhim xatoliklar tuzatilgan, lekin u sizning kodingizni buzadigan regressiyani ham o‘z ichiga oladi. Buni hal qilish uchun Rust birinchi marta cargo build dasturini ishga tushirganingizda Cargo.lock faylini yaratadi, shuning uchun biz endi bu guessing_game jildida mavjud.

Loyihani birinchi marta yaratganingizda, Cargo mezonlarga mos keladigan dependencylarning barcha versiyalarini aniqlaydi va keyin ularni Cargo.lock fayliga yozadi. Keyingi loyihangizni yaratganingizda, Cargo Cargo.lock fayli mavjudligini ko'radi va versiyalarni qayta aniqlash uchun barcha ishlarni bajarishdan ko'ra, u erda ko'rsatilgan versiyalardan foydalanadi. Bu sizga avtomatik ravishda takrorlanadigan tuzilishga ega bo'lish imkonini beradi. Boshqacha qilib aytganda, Cargo.lock fayli tufayli loyihangiz aniq yangilanmaguningizcha 0.8.5 da qoladi. Cargo.lock fayli qayta tiklanadigan tuzilmalar uchun muhim bo'lgani uchun u ko'pincha loyihangizdagi kodning qolgan qismi bilan manba nazoratida tekshiriladi.

Yangi versiyani olish uchun Crateni yangilash

Crateni yangilamoqchi bo'lsangiz, Cargo update buyrug'ini beradi, bu buyruq Cargo.lock faylini e'tiborsiz qoldiradi va Cargo.toml dagi texnik xususiyatlaringizga mos keladigan barcha so'nggi versiyalarni aniqlaydi. Keyin Cargo ushbu versiyalarni Cargo.lock fayliga yozadi. Aks holda, standart bo'yicha, Cargo faqat 0.8.5 dan katta va 0.9.0 dan kichik versiyalarni qidiradi. Agar rand cratesi ikkita yangi 0.8.6 va 0.9.0 versiyalarini chiqargan bo'lsa, cargo update ni ishga tushirgan bo'lsangiz, quyidagilarni ko'rasiz:

$ cargo update
    Updating crates.io index
    Updating rand v0.8.5 -> v0.8.6

Cargo 0.9.0 versiyasiga e'tibor bermaydi. Bu vaqtda siz Cargo.lock faylingizda oʻzgarishlarni ham sezasiz, bunda siz hozir foydalanayotgan rand cratesi versiyasi 0.8.6. rand 0.9.0 versiyasidan yoki 0.9.x seriyasining istalgan versiyasidan foydalanish uchun Cargo.toml faylini quyidagi koʻrinishda yangilashingiz kerak boʻladi:

[dependencies]
rand = "0.9.0"

Keyingi safar cargo buildni ishga tushirganingizda, Cargo mavjud cratelar reestrini yangilaydi va siz ko‘rsatgan yangi versiyaga muvofiq rand talablaringizni qayta baholaydi.

Cargo va uning ekotizimlari haqida ko'p gapirish mumkin, biz ularni 14-bobda muhokama qilamiz, ammo hozircha bilishingiz kerak bo'lgan narsa shu. Cargo kutubxonalarni qayta ishlatishni juda osonlashtiradi, shuning uchun Rustaceans bir nechta paketlardan yig'ilgan kichikroq loyihalarni yozishga qodir.

Tasodifiy raqamni yaratish

Keling, taxmin qilish uchun raqam yaratishda rand dan foydalanishni boshlaylik. Keyingi qadam 2-3 ro'yxatda ko'rsatilganidek src/main.rs ni yangilashdir.

Fayl nomi: src/main.rs

use std::io;
use rand::Rng;

fn main() {
    println!("Raqamni topish o'yini!");

    let yashirin_raqam = rand::thread_rng().gen_range(1..=100);

    println!("Yashirin raqam: {yashirin_raqam}");

    println!("Iltimos, taxminingizni kiriting.");

    let mut taxmin = String::new();

    io::stdin()
        .read_line(&mut taxmin)
        .expect("Satrni o‘qib bo‘lmadi");

    println!("Sizning taxminingiz: {taxmin}");
}

Ro'yxat 2-3: Tasodifiy raqam yaratish uchun kod qo'shiladi

Avval use rand::Rng; qatorini qo'shamiz. Rng traiti tasodifiy sonlar generatorlari qo'llaydigan metodlarni belgilaydi va biz ushbu usullardan foydalanishimiz uchun bu trait mos bo'lishi kerak. 10-bobda traitlar batafsil yoritiladi.

Keyin o'rtada ikkita qator qo'shamiz. Birinchi qatorda biz rand::thread_rng funksiyasini chaqiramiz, bu bizga biz foydalanmoqchi bo'lgan tasodifiy sonlar generatorini beradi: joriy bajarilish oqimi uchun mahalliy bo'lgan va operatsion tizim tomonidan ekilgan. Keyin tasodifiy sonlar generatorida gen_range metodini chaqiramiz. Bu metod biz use rand::Rng; iborasi bilan qamrab olgan Rng traiti bilan aniqlanadi. gen_range metodi argument sifatida diapazon ifodasini oladi va diapazonda tasodifiy son hosil qiladi. Biz bu yerda foydalanayotgan diapazon ifodasi turi start..=end shaklini oladi va pastki va yuqori chegaralarni qamrab oladi, shuning uchun biz 1 va 100 oralig‘idagi raqamni so‘rash uchun 1..=100 ni belgilashimiz kerak. .

Eslatma: Siz faqat qaysi traitlardan foydalanishni va qaysi metodlar va funktsiyalarni cratedan chaqirishni bila olmaysiz, shuning uchun har bir crateda foydalanish bo'yicha ko'rsatmalar mavjud. Cargo-ning yana bir qulay xususiyati shundaki, cargo doc --open buyrug'ini ishga tushirish sizning barcha dependencylar tomonidan taqdim etilgan texnik hujjatlarni mahalliy sifatida tuzadi va uni brauzeringizda ochadi. Agar siz rand cratedagi boshqa funksiyalarga qiziqsangiz, masalan, cargo doc --open ni ishga tushiring va chap tomondagi yon paneldagi rand tugmasini bosing.

Ikkinchi yangi qator maxfiy raqamni chop etadi. Bu dasturni ishlab chiqishda uni sinab ko'rishimiz uchun foydalidir, lekin biz uni oxirgi versiyadan o'chirib tashlaymiz. Agar dastur boshlanishi bilanoq javobni chop etsa, bu unchalik o'yin emas!

Dasturni bir necha marta ishga tushirishga harakat qiling:

$ cargo run
   Compiling taxminiy_raqam v0.1.0 (file:///projects/taxminiy_raqam)
    Finished dev [unoptimized + debuginfo] target(s) in 2.53s
     Running `target/debug/taxminiy_raqam`
Raqamni topish o'yini!
Yashirin raqam: 7
Iltimos, taxminingizni kiriting.
4
Siznig taxminingiz: 4

$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/taxminiy_raqam`
Raqamni topish o'yini!
Yashirin raqam: 83
Iltimos, taxminingizni kiriting.
5
Siznig taxminingiz: 5

Siz turli xil tasodifiy raqamlarni olishingiz kerak va ularning barchasi 1 dan 100 gacha raqamlar bo'lishi kerak. Ajoyib ish!

Taxminni maxfiy raqam bilan solishtirish

Endi bizda foydalanuvchi kiritishi va tasodifiy raqam bor, biz ularni solishtirishimiz mumkin. Ushbu qadam 2-4 ro'yxatda ko'rsatilgan. E'tibor bering, bu kod hozircha kompilatsiya bo'lmaydi, biz tushuntiramiz.

Fayl nomi: src/main.rs

use rand::Rng;
use std::cmp::Ordering;
use std::io;

fn main() {
    // --snip--
    println!("Raqamni topish o'yini!");

    let yashirin_raqam = rand::thread_rng().gen_range(1..=100);

    println!("Yashirin raqam: {yashirin_raqam}");

    println!("Iltimos, taxminingizni kiriting.");

    let mut taxmin = String::new();

    io::stdin()
        .read_line(&mut taxmin)
        .expect("Satrni o‘qib bo‘lmadi");

    println!("Sizning taxminingiz: {taxmin}");

    match taxmin.cmp(&yashirin_raqam) {
        Ordering::Less => println!("Raqam Kichik!"),
        Ordering::Greater => println!("Raqam katta!"),
        Ordering::Equal => println!("Siz yutdingiz!"),
    }
}

Ro'yxat 2-4: Ikki raqamni solishtirishning mumkin bo'lgan qaytish qiymatlarini boshqarish

Avval biz standart kutubxonadan std::cmp::Ording deb nomlangan turni olib keladigan yana bir use iborasini qo'shamiz. Ordering turi boshqa raqam boʻlib, Less, Greater va Equal variantlariga ega. Bu ikkita qiymatni solishtirganda mumkin bo'lgan uchta natijadir.

Keyin pastki qismida Ordering turidan foydalanadigan beshta yangi qator qo'shamiz. cmp metodi ikkita qiymatni solishtiradi va uni solishtirish mumkin bo'lgan har qanday narsani chaqirish mumkin. Siz solishtirmoqchi bo'lgan narsaga reference kerak: bu erda taxmin bilan yashirin_raqam solishtiriladi. Keyin u biz use iborasi bilan qamrab olgan Ordering raqamining variantini qaytaradi. Biz taxmin va yashirin_raqam qiymatlari bilan cmp ga murojatdan Ordering ning qaysi varianti qaytarilganiga qarab, keyin nima qilish kerakligini hal qilish uchun match ifodasidan foydalanamiz.

Match ifodasi arms dan tuzilgan. Arm mos keladigan pattern va agar match ga berilgan qiymat armning patterniga mos kelsa, bajarilishi kerak bo'lgan koddan iborat. Rust match ga berilgan qiymatni oladi va har bir armning patternini o'z navbatida ko'rib chiqadi. Patternlar va match konstruksiyasi Rust-ning kuchli xususiyatlari hisoblanadi: ular sizning kodingiz duch kelishi mumkin bo'lgan turli vaziyatlarni ifodalash imkonini beradi va ularning barchasini boshqarishingizga ishonch hosil qiladi. Bu xususiyatlar mos ravishda 6-bobda va 18-bobda batafsil yoritiladi.

Keling, bu yerda ishlatadigan match iborasi bilan bir misolni ko'rib chiqaylik. Aytaylik, foydalanuvchi 50 ni taxmin qilgan va bu safar tasodifiy yaratilgan maxfiy raqam 38 ni tashkil qiladi.

Kod 50 ni 38 ga solishtirganda, cmp metodi Ordering::Greater ni qaytaradi, chunki 50 38 dan katta. match ifodasi Ordering::Greater qiymatini oladi va har bir armning patternini tekshirishni boshlaydi. U birinchi armning Ordering::Less patternini koʻrib chiqadi va Ordering::Greater qiymati Ordering::Less qiymatiga mos kelmasligini koʻradi, shuning uchun u armdagi kodga eʼtibor bermaydi va keyingi armga oʻtadi. Keyingi armning namunasi Ordering::Greater boʻlib, Ordering::Greater bilan does match keladi! Oʻsha armdagi bogʻlangan kod ishga tushadi va ekranga Raqam katta! deb chop etiladi. match iborasi birinchi muvaffaqiyatli o'yindan keyin tugaydi, shuning uchun bu senariydagi oxirgi armni ko'rib chiqmaydi.

Biroq, 2-4 ro'yxatdagi kod hali kompilyatsiya qilinmaydi. Keling, sinab ko'raylik:

$ cargo build
   Compiling libc v0.2.86
   Compiling getrandom v0.2.2
   Compiling cfg-if v1.0.0
   Compiling ppv-lite86 v0.2.10
   Compiling rand_core v0.6.2
   Compiling rand_chacha v0.3.0
   Compiling rand v0.8.5
   Compiling taxminiy_raqam v0.1.0 (file:///projects/taxminiy_raqam)
error[E0308]: mismatched types
  --> src/main.rs:22:21
   |
22 |     match taxmin.cmp(&yashirin_raqam) {
   |                 --- ^^^^^^^^^^^^^^ expected struct `String`, found integer
   |                 |
   |                 arguments to this function are incorrect
   |
   = note: expected reference `&String`
              found reference `&{integer}`
note: associated function defined here
  --> /rustc/d5a82bbd26e1ad8b7401f6a718a9c57c96905483/library/core/src/cmp.rs:783:8

For more information about this error, try `rustc --explain E0308`.
error: could not compile `taxminiy_raqame` due to previous error

Xatoning asosi mos kelmaydigan turlar mavjudligini bildiradi. Rust kuchli, statik turdagi tizimga ega. Biroq, u ham turdagi inference ega. Biz let mut taxmin = String::new() deb yozganimizda, Rust taxmin String bo'lishi kerak degan xulosaga keldi va bizni turni yozishga majburlamadi. Boshqa tomondan, yashirin_raqam raqam turidir. Rust raqamlarining bir nechta turlari 1 dan 100 gacha qiymatga ega bo'lishi mumkin: i32, 32 bitli raqam; u32, unsigned 32-bitli raqam; i64, 64-bitli raqam; boshqalar kabi. Agar boshqacha koʻrsatilmagan boʻlsa, Rust standart boʻyicha i32 ga oʻrnatiladi, bu yashirin_raqam turiga, agar siz Rustning boshqa raqamli turini chiqarishiga olib keladigan turdagi maʼlumotlarni boshqa joyga qoʻshmasangiz. Xatoning sababi shundaki, Rust string va raqam turini taqqoslay olmaydi.

Oxir-oqibat, biz dastur tomonidan kiritilgan String ni haqiqiy son turiga aylantirmoqchimiz, shuning uchun uni raqamli raqam bilan yashirin raqam bilan solishtirishimiz mumkin.Buni main funksiya tanasiga ushbu qatorni qo'shish orqali qilamiz:

Fayl nomi: src/main.rs

use rand::Rng;
use std::cmp::Ordering;
use std::io;

fn main() {
    println!("Raqamni topish o'yini!");

    let yashirin_raqam = rand::thread_rng().gen_range(1..=100);

    println!("Yashirin raqam: {yashirin_raqam}");

    println!("Iltimos, taxminingizni kiriting.");

    // --snip--

    let mut taxmin = String::new();

    io::stdin()
        .read_line(&mut taxmin)
        .expect("Satrni o‘qib bo‘lmadi");

    let taxmin: u32 = taxmin.trim().parse().expect("Iltimos, raqam yozing!");

    println!("Sizning taxminingiz: {taxmin}");

    match taxmin.cmp(&yashirin_raqam) {
        Ordering::Less => println!("Raqam Kichik!"),
        Ordering::Greater => println!("Raqam katta!"),
        Ordering::Equal => println!("Siz yutdingiz!"),
    }
}

Satr

let taxmin: u32 = taxmin.trim().parse().expect("Iltimos, raqam yozing!");

Biz taxmin nomli o'zgaruvchini yaratamiz. Ammo shoshilmang, dasturda allaqachon taxmin nomli o'zgaruvchi mavjud emasmi? Bu shunday, lekin foydali Rust bizga taxmin ning oldingi qiymatini yangisi bilan ergashtirish imkonini beradi. Shadowing bizga ikkita noyob oʻzgaruvchini yaratish oʻrniga, taxmin oʻzgaruvchi nomidan qayta foydalanish imkonini beradi, masalan, taxmin_str va taxmin. Biz buni 3-bobda batafsil ko'rib chiqamiz, ammo hozircha shuni bilingki, bu xususiyat ko'pincha qiymatni bir turdan boshqa turga aylantirmoqchi bo'lganingizda ishlatiladi.

Biz bu yangi o'zgaruvchini taxmin.trim().parse() ifodasiga bog'laymiz. Ifodadagi taxmin matni qator sifatida kiritilgan asl taxmin o'zgaruvchisiga ishora qiladi. String misolidagi trim metodi boshida va oxiridagi har qanday bo‘shliqni yo‘q qiladi, bu qatorni faqat raqamli ma’lumotlarni o‘z ichiga olishi mumkin bo‘lgan u32 bilan solishtirishimiz uchun buni qilishimiz kerak. Foydalanuvchi read_line ni to'ldirish uchun entertugmasini bosib, ularni kiritishi kerak satrga yangi satr belgisini qo'shadigan taxmin. Masalan, agar foydalanuvchi 5 raqamini kiritsa va va enter tugmasini bossa taxmin shunday ko'rinadi: 5\n. \n “yangi qator”ni bildiradi. (Windows tizimida enter tugmasini bosish natijasida carriage qaytariladi va yangi qator \r\n chiqadi.) trim metodi \n yoki \r\nni yo'q qiladi, natijada atigi 5 bo`ladi.

Satrlardagi parse metodi qatorni boshqa turga aylantiradi. Bu yerda biz uni stringdan raqamga aylantirish uchun foydalanamiz. Biz Rustga let taxmin: u32 yordamida kerakli raqam turini aytishimiz kerak. taxmin dan keyin ikki nuqta (:) Rustga o'zgaruvchining turiga izoh berishimizni aytadi. Rust bir nechta o'rnatilgan raqam turlariga ega; Bu yerda koʻrilgan u32 unsigned, 32-bitli butun son. Bu kichik ijobiy raqam uchun yaxshi standart tanlovdir. Boshqa raqamlar turlari haqida 3-bobda bilib olasiz.

Bundan tashqari, ushbu misol dasturidagi u32 annotation va yashirin_raqam bilan taqqoslash Rust yashirin_raqam ham u32 bo'lishi kerak degan xulosaga keladi. Shunday qilib, endi taqqoslash bir xil turdagi ikkita qiymat o'rtasida bo'ladi!

parse metodii faqat mantiqiy ravishda raqamlarga aylantirilishi mumkin bo'lgan belgilarda ishlaydi va shuning uchun osongina xatolarga olib kelishi mumkin. Agar, masalan, satrda A👍% bo'lsa, uni raqamga aylantirishning hech qanday metodi bo'lmaydi. Muvaffaqiyatsiz bo'lishi mumkinligi sababli, parse metodii read_line metodi kabi Result turini qaytaradi (oldingi ["Result bilan potentsial muvaffaqiyatsizlikni ko'rib chiqish"] bo'limida muhokama qilingan)(#handling-potential-failure-with-result)). Biz ushbu Result ga yana expect metodini qo'llash orqali xuddi shunday munosabatda bo'lamiz. Agar parse qatordan raqam yarata olmagani uchun Err Result variantini qaytarsa, expect chaqiruvi o‘yinni buzadi va biz bergan xabarni chop etadi. Agar parse qatorni raqamga muvaffaqiyatli aylantira olsa, u Resultning Ok variantini qaytaradi va expect biz xohlagan raqamni Ok qiymatidan qaytaradi.

Endi dasturni ishga tushiramiz:

$ cargo run
   Compiling taxminiy_raqam v0.1.0 (file:///projects/taxminiy_raqam)
    Finished dev [unoptimized + debuginfo] target(s) in 0.43s
     Running `target/debug/taxminiy_raqam`
Raqamni topish o'yini!
Yashirin raqam: 58
Iltimos, taxminingizni kiriting.
  76
Sizning taxminingiz: 76
Raqam katta!

Yaxshi! Tahmindan oldin bo'shliqlar qo'shilgan bo'lsa ham, dastur foydalanuvchi 76 ni taxmin qilganini aniqladi. Har xil turdagi kirishlar bilan turli xatti-harakatlarni tekshirish uchun dasturni bir necha marta ishga tushiring: raqamni to'g'ri taxmin qiling, katta raqamni taxmin qiling va kichik raqamni taxmin qiling.

Hozir bizda o'yinning ko'p qismi ishlayapti, lekin foydalanuvchi faqat bitta taxmin qila oladi. Keling, buni loop qo'shish orqali o'zgartiraylik!

Loop bilan bir nechta taxminlarga ruxsat berish

loop kalit so'zi cheksiz tsiklni yaratadi. Biz foydalanuvchilarga raqamni taxmin qilishda ko'proq imkoniyat berish uchun tsikl qo'shamiz: Fayl nomi: src/main.rs

use rand::Rng;
use std::cmp::Ordering;
use std::io;

fn main() {
    println!("Raqamni topish o'yini!");

    let yashirin_raqam = rand::thread_rng().gen_range(1..=100);

    // --snip--

    println!("Yashirin raqam: {yashirin_raqam}");

    loop {
        println!("Iltimos, taxminingizni kiriting.");

        // --snip--


        let mut taxmin = String::new();

        io::stdin()
            .read_line(&mut taxmin)
            .expect("Satrni o‘qib bo‘lmadi");

        let taxmin: u32 = taxmin.trim().parse().expect("Iltimos, raqam yozing!");

        println!("Sizning taxminingiz: {taxmin}");

        match taxmin.cmp(&yashirin_raqam) {
            Ordering::Less => println!("Raqam Kichik!"),
            Ordering::Greater => println!("Raqam katta!"),
            Ordering::Equal => println!("Siz yutdingiz!"),
        }
    }
}

Ko'rib turganingizdek, biz hamma narsani taxminiy kiritish so'rovidan boshlab tsiklga o'tkazdik. Ilova ichidagi satrlarni har birida yana to'rtta bo'sh joydan o'tkazganingizga ishonch hosil qiling va dasturni qayta ishga tushiring. Dastur endi boshqa bir taxminni abadiy yani har doim so'raydi, bu aslida yangi muammoni keltirib chiqaradi. Foydalanuvchi chiqa olmaydiganga o'xshaydi!

Foydalanuvchi har doim ctrl-c klaviatura yorlig'i yordamida dasturni to'xtatishi mumkin. Ammo bu to'yib bo'lmaydigan yirtqich hayvondan qochishning yana bir yo'li bor, “Taxminni maxfiy raqam bilan solishtirish“: mavzusidagi parse muhokamasida aytib o'tilganidek, agar foydalanuvchi raqam bo'lmagan javobni kiritsa, dastur buziladi. Bu yerda ko'rsatilganidek, foydalanuvchiga chiqishga ruxsat berish uchun undan foydalanishimiz mumkin

$ cargo run
   Compiling taxminiy_raqam v0.1.0 (file:///projects/taxminiy_raqam)
    Finished dev [unoptimized + debuginfo] target(s) in 1.50s
     Running `target/debug/taxminiy_raqam`
Raqamni topish o'yini!
Yashirin raqam: 59
Iltimos, taxminingizni kiriting.
45
Sizning taxminingiz: 45
Raqam Kichik!
Iltimos, taxminingizni kiriting.
60
Sizning taxminingiz: 60
Raqam katta!
Iltimos, taxminingizni kiriting.
59
Sizning taxminingiz: 59
Siz yutdingiz!
Iltimos, taxminingizni kiriting.
quit
thread 'main' panicked at 'Please type a number!: ParseIntError { kind: InvalidDigit }', src/main.rs:28:47
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

quit deb yozsangiz, o‘yin tugaydi, lekin siz ko‘rganingizdek, boshqa raqam bo‘lmagan ma’lumotlarni kiritish ham shunday bo‘ladi. Bu, eng kamida, suboptimaldir; Biz to'g'ri raqam taxmin qilinganda ham o'yin to'xtashini xohlaymiz.

To'g'ri taxmindan keyin chiqish

Keling, foydalanuvchi g'alaba qozonganida break iborasini qo'shish orqali o'yinni to'xtatish uchun dasturlashtiramiz:

Fayl nomi: src/main.rs

use rand::Rng;
use std::cmp::Ordering;
use std::io;

fn main() {
    println!("Raqamni topish o'yini!");

    let yashirin_raqam = rand::thread_rng().gen_range(1..=100);

    println!("Yashirin raqam: {yashirin_raqam}");

    loop {
        println!("Iltimos, taxminingizni kiriting.");

        let mut taxmin = String::new();

        io::stdin()
            .read_line(&mut taxmin)
            .expect("Satrni o‘qib bo‘lmadi");

        let taxmin: u32 = taxmin.trim().parse().expect("Iltimos, raqam yozing!");

        println!("Sizning taxminingiz: {taxmin}");

        // --snip--

        match taxmin.cmp(&yashirin_raqam) {
            Ordering::Less => println!("Raqam Kichik!"),
            Ordering::Greater => println!("Raqam katta!"),
            Ordering::Equal => {
                println!("Siz yutdingiz!");
                break;
            }
        }
    }
}

Siz yutdingiz! so‘ng break qatorini qo‘shish foydalanuvchi maxfiy raqamni to‘g‘ri taxmin qilganda dasturni tsikldan chiqadi. Loopdan chiqish dasturdan chiqishni ham anglatadi, chunki sikl main ning oxirgi qismidir.

Noto'g'ri kiritish

O'yinning xatti-harakatlarini yanada yaxshilash uchun, foydalanuvchi raqamlardan boshqa belgilar kiritganda dasturni ishdan chiqargandan ko'ra, foydalanuvchi taxmin qilishni davom ettirishi uchun o'yinni raqam bo'lmagan belgilarga e'tibor bermaslikka harakat qildiraylik. Buni 2-5 roʻyxatda koʻrsatilganidek, taxmin satrdan u32 ga aylantirilgan qatorni oʻzgartirish orqali amalga oshirishimiz mumkin.

Fayl nomi: src/main.rs

use rand::Rng;
use std::cmp::Ordering;
use std::io;

fn main() {
    println!("Raqamni topish o'yini!");

    let yashirin_raqam = rand::thread_rng().gen_range(1..=100);

    println!("Yashirin raqam: {yashirin_raqam}");

    loop {
        println!("Iltimos, taxminingizni kiriting.");

        let mut taxmin = String::new();

        // --snip--

        io::stdin()
            .read_line(&mut taxmin)
            .expect("Satrni o‘qib bo‘lmadi");

        let taxmin: u32 = match taxmin.trim().parse() {
            Ok(num) => num,
            Err(_) => continue,
        };

        println!("Sizning taxminingiz: {taxmin}");

        // --snip--

        match taxmin.cmp(&yashirin_raqam) {
            Ordering::Less => println!("Raqam Kichik!"),
            Ordering::Greater => println!("Raqam katta!"),
            Ordering::Equal => {
                println!("Siz yutdingiz!");
                break;
            }
        }
    }
}

Ro'yxat 2-5: Raqamsiz taxminga e'tibor bermaslik va dasturni ishdan chiqarish o'rniga boshqa taxminni so'rash

Xato ustida ishlamay qolishdan xatoni hal qilishga o‘tish uchun biz expect chaqiruvidan match ifodasiga o‘tamiz. Esda tutingki, parse Result turini qaytaradi, Result esa Ok va Err variantlariga ega bo'lgan raqamdir. Biz bu yerda cmp metodining Ordering natijasi bilan bo‘lgani kabi match ifodasidan foydalanmoqdamiz.

Agar parse qatorni raqamga muvaffaqiyatli aylantira olsa, natijada olingan raqamni o'z ichiga olgan Ok qiymatini qaytaradi. Bu Ok qiymati birinchi armning patterniga mos keladi va match ifodasi parse ishlab chiqarilgan va Ok qiymatiga qo'ygan num qiymatini qaytaradi. Bu raqam biz yaratayotgan yangi taxmin o'zgaruvchisida biz xohlagan joyda tugaydi

Agar parse satrni raqamga aylantira olmasa xato haqida qo'shimcha ma'lumotni o'z ichiga olgan Err qiymatini qaytaradi. Err qiymati birinchi match bo‘limidagi Ok(num) patterniga mos kelmaydi, lekin ikkinchi armdagi Err(_) patterniga mos keladi. Pastki chiziq, _, diqqatga sazovor qiymatdir; bu misolda biz barcha Err qiymatlariga, ular ichida qanday ma'lumotlar bo'lishidan qat'iy nazar, mos kelmoqchimiz deymiz. Shunday qilib, dastur ikkinchi armning continue kodini bajaradi, bu dasturga loop ning keyingi iteratsiyasiga o'tishni va boshqa taxminni so'rashni aytadi. Shunday qilib, dastur parse duch kelishi mumkin bo'lgan barcha xatolarga e'tibor bermaydi!

Endi dasturdagi hamma narsa kutilganidek ishlashi kerak. Keling, sinab ko'raylik:

$ cargo run
   Compiling taxminiy_raqam v0.1.0 (file:///projects/taxminiy_raqam)
    Finished dev [unoptimized + debuginfo] target(s) in 4.45s
     Running `target/debug/taxminiy_raqam`
Raqamni topish o'yini!
Yashirin raqam: 61
Iltimos, taxminingizni kiriting.
10
Sizning taxminingiz: 10
Raqam Kichik!
Iltimos, taxminingizni kiriting.
99
Sizning taxminingiz: 99
Raqam katta!
Iltimos, taxminingizni kiriting.
foo
Iltimos, taxminingizni kiriting.
61
Sizning taxminingiz: 61
Siz yutdingiz!

Ajoyib! Bitta kichik so'nggi tweak bilan biz taxmin qilish o'yinini tugatamiz. Eslatib o'tamiz, dastur hali ham maxfiy raqamni chop etmoqda. Bu sinov uchun yaxshi ishladi, lekin o'yinni buzadi. Maxfiy raqamni chiqaradigan println!ni o'chirib tashlaymiz. 2-6 ro'yxat yakuniy kodni ko'rishingiz mumkin.

Fayl nomi: src/main.rs

use rand::Rng;
use std::cmp::Ordering;
use std::io;

fn main() {
    println!("Raqamni topish o'yini!");

    let yashirin_raqam = rand::thread_rng().gen_range(1..=100);

    loop {
        println!("Iltimos, taxminingizni kiriting.");

        let mut taxmin = String::new();

        io::stdin()
            .read_line(&mut taxmin)
            .expect("Satrni o‘qib bo‘lmadi");

        let taxmin: u32 = match taxmin.trim().parse() {
            Ok(num) => num,
            Err(_) => continue,
        };

        println!("Sizning taxminingiz: {taxmin}");

        match taxmin.cmp(&yashirin_raqam) {
            Ordering::Less => println!("Raqam Kichik!"),
            Ordering::Greater => println!("Raqam katta!"),
            Ordering::Equal => {
                println!("Siz yutdingiz!");
                break;
            }
        }
    }
}

Ro'yxat 2-6: To'liq taxmin qilish o'yin kodini

Shu nuqtada, siz taxmin qilish o'yinini muvaffaqiyatli yaratdingiz. Tabriklaymiz!

Xulosa

Ushbu loyiha sizni Rustning ko'plab yangi tushunchalari bilan tanishtirishning amaliy usuli bo'ldi: let, match, funktsiyalar, tashqi cratelardan foydalanish va boshqalar. Keyingi bir necha boblarda siz ushbu tushunchalar haqida batafsilroq bilib olasiz. 3-bob ko'pchilik dasturlash tillarida mavjud bo'lgan o'zgaruvchilar, ma'lumotlar turlari va funktsiyalari kabi tushunchalarni qamrab oladi va ulardan Rustda qanday foydalanishni ko'rsatadi. 4-bobda Rust tilini boshqa tillardan ajratib turadigan egalik huquqi o‘rganiladi. 5-bobda tuzilmalar va metodlar sintaksisi muhokama qilinadi va 6-bobda enumlar qanday ishlashi tushuntiriladi.