Məzmuna keç
Educora
Orta20 dəq5 / 10

Strukturlar, metodlar, enum və match

Öz tiplərini yarat: sahələri olan strukturlar, `impl` bloku ilə metodlar, variantları olan `enum`-lar, onları `match` ilə emal etmək və `null` əvəzinə `Option`.

Özünü yoxla
Bu dərsdə öyrənəcəksən
  • Struktur elan etmək, onun nümunəsini yaratmaq və #[derive(Debug)] ilə çap etmək
  • impl blokunda &self, &mut self metodları və əlaqəli funksiyalar yazmaq
  • Məlumat daşıyan variantları olan enum yaratmaq və onu tam match ilə emal etmək
  • Olmaya bilən qiyməti Option, if let və unwrap_or ilə təhlükəsiz idarə etmək

Elektron jurnalda hər şagirdin adı, sinfi və orta balı var — bu üç qiyməti ayrı-ayrı dəyişənlərdə saxlamaq əlverişsizdir, onları bir yerdə saxlamaq lazımdır. Svetofor isə eyni anda yalnız bir vəziyyətdə olur: qırmızı, sarı və ya yaşıl. Rust-da birinci hal üçün strukturlar (struct), ikinci hal üçün sadalamalar (enum) var.

Strukturlar

Struktur adlı sahələri olan tipdir. Tipin adı PascalCase ilə, sahələr isə snake_case ilə yazılır. Nümunə yaradanda bütün sahələrə qiymət verilməlidir, sahəyə isə nöqtə ilə müraciət olunur: aysel.score. Sahəni dəyişmək üçün bütün nümunə mut olmalıdır — Rust-da ayrıca sahəni mut etmək olmur.

Rust
#[derive(Debug)]
struct Student {
    name: String,
    grade: u8,
    score: f64,
}

fn main() {
    let mut aysel = Student {
        name: String::from("Aysel"),
        grade: 9,
        score: 91.5,
    };
    aysel.score += 2.0;
    println!("{} is in grade {}", aysel.name, aysel.grade);
    println!("{:?}", aysel);
    println!("{:#?}", aysel);
}
Gözlənilən nəticə
Aysel is in grade 9
Student { name: "Aysel", grade: 9, score: 93.5 }
Student {
    name: "Aysel",
    grade: 9,
    score: 93.5,
}
#[derive(Debug)] atributu kompilyatora strukturu {:?} ilə çap etməyi öyrədir. {:#?} isə hər sahəni ayrıca sətirdə, səliqəli göstərir.

Metodlar və impl

Tipə aid funksiyalar impl blokunda yazılır. Birinci parametri self olan funksiya metoddur və nöqtə ilə çağırılır: room.area(). self parametri olmayan funksiya isə əlaqəli funksiyadır, :: ilə çağırılır: Rectangle::new(4, 3) — String::from da məhz belədir. impl daxilində Self yazılışı tipin öz adını əvəz edir.

Rust
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn new(width: u32, height: u32) -> Self {
        Self { width, height }
    }

    fn area(&self) -> u32 {
        self.width * self.height
    }

    fn scale(&mut self, factor: u32) {
        self.width *= factor;
        self.height *= factor;
    }
}

fn main() {
    let mut room = Rectangle::new(4, 3);
    println!("Area: {}", room.area());
    room.scale(2);
    println!("Scaled: {}x{}, area {}", room.width, room.height, room.area());
}
Gözlənilən nəticə
Area: 12
Scaled: 8x6, area 48
Birinci parametrMənasıÇağırış
&selfnümunəni yalnız oxuyurroom.area()
&mut selfnümunəni dəyişirroom.scale(2)
selfsahibliyi götürür, nümunə sonra istifadə olunmurtext.into_bytes()
self yoxdurəlaqəli funksiya, çox vaxt konstruktorRectangle::new(4, 3)

Enum və match

enum qiymətin bir neçə variantdan biri olduğunu bildirir. Rust-da variantlar öz məlumatlarını da daşıya bilər: heç nə, adlı sahələr və ya mötərizədə qiymətlər. Enum-u match ilə emal edirlər: hər qol nümunə => ifadə şəklindədir. match tam olmalıdır — hər mümkün variant nəzərə alınmalıdır, əks halda kod kompilyasiya olunmur.

Rust
enum Command {
    Quit,
    Move { x: i32, y: i32 },
    Say(String),
}

fn run(cmd: &Command) -> String {
    match cmd {
        Command::Quit => String::from("bye"),
        Command::Move { x, y } => format!("move to ({x}, {y})"),
        Command::Say(text) => format!("say: {text}"),
    }
}

fn main() {
    let commands = [
        Command::Say(String::from("hello")),
        Command::Move { x: 3, y: -1 },
        Command::Quit,
    ];
    for cmd in &commands {
        println!("{}", run(cmd));
    }
}
Gözlənilən nəticə
say: hello
move to (3, -1)
bye
format! println! kimi işləyir, amma mətni ekrana çıxarmır, String kimi qaytarır. match qolunda x, y və text variantın içindəki məlumatla bağlanır.
Xəta E0004
fn day_type(day: u8) -> char {
    match day {
        1..=5 => 'W',
        6 | 7 => 'H',
    }
}
`_` ilə tam
fn day_type(day: u8) -> char {
    match day {
        1..=5 => 'W',
        6 | 7 => 'H',
        _ => '?',
    }
}
u8 0-dan 255-ə qədər ola bilər, ona görə kompilyator yazır: non-exhaustive patterns: 0_u8 and 8_u8..=u8::MAX not covered. _ «qalan hər şey» deməkdir. Nümunələrdə diapazon (1..=5) və «və ya» (6 | 7) da işlətmək olar.

null əvəzinə Option

Rust-da null yoxdur. Qiymət ola da, olmaya da bilərsə, standart kitabxanadakı Option<T> enum-u işlədilir: Some(qiymət) və ya None. Onun içindəki qiymətdən birbaşa istifadə etmək olmaz — kompilyator səni None halını da nəzərə almağa məcbur edir. Yalnız bir variant maraqlıdırsa, uzun match əvəzinə qısa if let yazmaq olar.

Rust
fn find_index(names: &[&str], target: &str) -> Option<usize> {
    for (i, name) in names.iter().enumerate() {
        if *name == target {
            return Some(i);
        }
    }
    None
}

fn main() {
    let names = ["Elvin", "Leyla", "Murad"];
    match find_index(&names, "Leyla") {
        Some(i) => println!("Leyla is at {i}"),
        None => println!("Leyla not found"),
    }
    if let Some(i) = find_index(&names, "Nigar") {
        println!("Nigar is at {i}");
    } else {
        println!("Nigar not found");
    }
    let murad = find_index(&names, "Murad");
    println!("{:?} {}", murad, murad.unwrap_or(0));
}
Gözlənilən nəticə
Leyla is at 1
Nigar not found
Some(2) 2
unwrap_or(0) Some içindəki qiyməti, None olduqda isə verilən ehtiyat qiyməti qaytarır. Standart kitabxanada eyni işi görən hazır metod da var: names.iter().position(|n| *n == target).

Əsas fikirlər

  • struct adlı sahələri bir tipdə birləşdirir; #[derive(Debug)] onu {:?} ilə çap etməyə imkan verir.
  • Metodlar impl blokunda yazılır: &self oxuyur, &mut self dəyişir; self-siz funksiya Tip::ad() ilə çağırılır.
  • enum variantları məlumat daşıya bilər; match bütün variantları əhatə etməlidir, _ qalanları tutur.
  • Rust-da null yoxdur: olmaya bilən qiymət Option<T> — Some(x) və ya None — ilə ifadə olunur.
  • unwrap() None-da panikaya düşür; match, if let və unwrap_or daha təhlükəsizdir.

Özünü yoxla

10 sual. Hər düzgün cavab XP qazandırır.

1 / 10
Hansı metod imzası strukturun sahələrini dəyişməyə imkan verir?