03. Още за &низове и структури

03. Още за &низове и структури

03. Още за &низове и структури

13 октомври 2017

Административни неща

Преговор

Странности от миналата лекция

(неща, които изненадаха Андрей)

let r;
{
    r = String::new("foobar");
}
println!("{}", r);

Странности от миналата лекция

(неща, които изненадаха Андрей)

let x;
println!("{}", x = 3); // wat

Странности от миналата лекция

(неща, които изненадаха целия екип)

println!("{x} {y} {z}", x = 3, z = 1, y = 2);

rustc 1.21.0 🎉

Масиви

let a: [i32; 5] = [1, 2, 3, 4, 5];

let elem = a[2];
println!("{}", elem);   // 3

Масиви

Многоизмерни масиви

let a: [[i32; 5]; 3] = [
    [01, 02, 03, 04, 05],
    [11, 12, 13, 14, 15],
    [21, 22, 23, 24, 25],
];

let elem_1_2 = a[1][2];
println!("{}", elem_1_2);   // ?

Масиви

Пропускане на типа

// ако работи - добре
let a = [1, 2, 3, 4, 5];

// ако не - трябва да кажем типа на поне един елемент
let a = [1_i32, 2, 3, 4, 5];
let a = [1, 2, 3_i32, 4, 5];
let a = [1, 2, 3, 4, 5_i32];

let a = [
    [01, 02, 03, 04, 05],
    [11, 12, 13, 14, 15],
    [21, 22, 23, 24, 25_i32],
];

Динамични масиви

Вектори

let a = vec![1, 2, 3, 4, 5];

let elem = a[2];
println!("{}", elem);   // 3

Динамични масиви

vec!

let a = vec![1, 2, 3, 4, 5];

Еквивалентно на

let a = {
    let mut tmp = Vec::new();
    tmp.push_back(1);
    tmp.push_back(2);
    tmp.push_back(3);
    tmp.push_back(4);
    tmp.push_back(5);
    tmp
};

Динамични масиви

Разполагане в паметта

Взимане на елемент

let v = vec![String::from("баба"), String::from("дядо")];

let baba = v[0];    // грешка, String не е Copy

Взимане на елемент

let v = vec![String::from("баба"), String::from("дядо")];

let baba = &v[0];
let dqdo = &v[1];
// let vnuche = &v[2]; // грешка при изпълнение

Взимане на елемент

let v = vec![String::from("баба"), String::from("дядо")];

let baba = &v[0];
let dqdo = &v[1];

v.push_back(String::from("внуче"));   // грешка

Заемане на част от структура

Можем да заемаме отделни части от структури и кортежи

let x = (1, 2);

let r1 = &x;
let r2 = &x.0;
let r3 = &x.1;

Заемане на част от структура

Отделните части се считат като отделни стойности от borrow checker-a

let mut x = (1, 2);

let r1 = &mut x.0;
let r2 = &mut x.1;

let r1 = &mut x.0;
let r2 = &mut x.0;  // грешка

Заемане на част от структура

Но се считат и като заемане на цялата структура

let mut x = (1, 2);

let r1 = &x.0;
let r2 = &mut x;  // грешка

let r1 = &mut x.0;
let r2 = &x       // грешка

Заемане на част от масив

let mut a = [String::from("баба"), String::from("дядо")];

let baba = &mut a[0];
let dqdo = &mut a[1];   // ?

Заемане на част от масив

Резени

Резени

(Slices)

let s = String::from("hello world");

let hello = &s[0..5];
let world = &s[6..11];

println!("{} {}", hello, world);

Резени

(Slices)

Резени

(Slices)

let s = String::from("hello");
let len = s.len();

let slice = &s[0..2];
let slice = &s[..2];

let slice = &s[3..len];
let slice = &s[3..];

let slice = &s[..];

Резени

(Slices)

fn first_word(s: &String) -> &str {
    let mut i = 0;

    for byte in s.bytes() {
        if byte == b' ' {
            return &s[0..i];
        }
        i += 1;
    }

    &s[..]
}

Резени

(Slices)

Какво става, ако не е псевдоним?

let s = String::from("hello world");
let hello = s[0..5];

println!("{}", hello);
error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
--> src/main.rs:3:9
  |
3 |     let hello = s[0..5];
  |         ^^^^^ `str` does not have a constant size known at compile-time
  |
  = help: the trait `std::marker::Sized` is not implemented for `str`
  = note: all local variables must have a statically known size

Смесване на типове

fn first_word(s: &String) -> &str { /* ... */ }
fn first_word(s: &str) -> &str { /* ... */ }

Смесване на типове

fn main() {
    let hello = String::from("hello world");
    let word = first_word(&hello[..]); // slice от String

    let hello = "hello world";
    let word = first_word(&hello[..]); // slice от &str
    let word = first_word(hello);      // директно подаваме &str
}

Deref coercion

Правила за автоматично конвертиране от един тип псевдоним до друг

Използват се само при:

Примери

Смесване на типове

fn main() {
    let hello = String::from("hello world");
    let word = first_word(&hello);      // еквивалентно на &hello[..]
    let len = hello.len();              // автоматично конвентира до &str и извиква метода му len

    let hello = "hello world";
    let word = first_word(hello);       // директно подаваме &str
    let len = hello.len();              // директно извикваме метода len
}

Статични низове

let s: &'static str = "Hello, world!";

Structs

struct User {
    username:      String,
    email:         String,
    sign_in_count: u64,
    active:        bool,
}

Structs

fn main() {
    let baba = User {
        email:         String::from("baba@abv.bg"),
        username:      String::from("baba_1337"),
        active:        true,
        sign_in_count: 1,
    };

    println!("{:?}", baba); // грешка, за момента
}

Structs

атрибут derive

#[derive(Debug)]
struct User {
    username:      String,
    email:         String,
    sign_in_count: u64,
    active:        bool,
}

Structs

fn main() {
    let baba = User {
        email:         String::from("baba@abv.bg"),
        username:      String::from("baba_1337"),
        active:        true,
        sign_in_count: 1,
    };

    println!("{:?}", baba);
    // => User { username: "baba_1337", email: "baba@abv.bg", sign_in_count: 1, active: true }
}

Structs

field mutability

let baba = User { /* ... */ };

// baba.email = String::from("hackerman@l33t.hax"); // грешка

let mut baba = baba;

baba.email = String::from("hackerman@l33t.hax");

Structs

update syntax

let hackerman = User {
    email:          String::from("hackerman@l33t.hax"),
    username:       String::from(""),
    active:         baba.active,
    sign_in_count:  baba.sign_in_count,
};

println!("{:?}", hackerman);
// => User { username: "", email: "hackerman@l33t.hax", sign_in_count: 1, active: true }

Structs

update syntax

let hackerman = User {
    email:    String::from("hackerman@l33t.hax"),
    username: String::from(""),
    ..baba,
};

println!("{:?}", hackerman);
// => User { username: "", email: "hackerman@l33t.hax", sign_in_count: 1, active: true }

Tuple Structs

(кортежни структури? структурни кортежи?)

struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);

Unit Structs

struct Electron {} // Празни скоби...
struct Proton;     // ...или просто точка и запетая.

// Използвайте същата нотация когато инстанцирате структурата.
let x = Electron {};
let y = Proton;
// let z = Electron; // грешка

Structs: what about &str

А защо не &str вместо String?

struct User {
    username:      &str, // ???
    email:         &str, // ???
    sign_in_count: u64,
    active:        bool,
}
error[E0106]: missing lifetime specifier
--> src/main.rs:3:20
  |
3 |     username:      &str,
  |                    ^ expected lifetime parameter

...

Lifetimes

... са неща, за които ще говорим после

Просто използвайте String засега

Методи

#[derive(Debug)]
struct Rectangle {
    length: u32,
    width: u32,
}

fn main() {
    let r = Rectangle { length: 50, width: 30 };

    println!(
        "Площта на правоъгълника е {}px²",
        r.length * r.width
    );
}

Методи

#[derive(Debug)]
struct Rectangle {
    length: u32,
    width: u32,
}

impl Rectangle {
    fn area(&self) -> u32 {
        self.length * self.width
    }
}

Методи

fn main() {
    let r = Rectangle { length: 50, width: 30 };

    println!(
        "Площта на правоъгълника е {}px²",
        r.area()
    );
}

Методи

какво е self?

impl Rectangle {
    fn area(self: &Rectangle) -> u32 {
        self.length * self.width
    }
}

Методи

видове дефиниции

impl SomeStructType {
    fn method_borrows(&self) -> u32 { 42 }

    fn method_borrows_mutably(&mut self) -> u32 { 42 }

    fn method_takes_ownership(self) -> u32 { 42 }
}

Методи

mutable borrow

// impl std::string::String {
fn push_str(&mut self, string: &str) {

let mut s = String::from("hello");
// let s2 = &mut s; // грешка
s.push_str(", world");

Методи

Deref coercion

struct Point { x: f64, y: f64 };

impl Point {
    fn distance(self: &Point, other: &Point) -> f64 {
        // ...
    }
}

p1.distance(&p2);
(&&&p1).distance(&&&&&&p2);

Методи

Deref coercion

RustC
(&instance).field(*(&instance)).fieldinstance->field
(&&&instance).field(***(&&&instance)).field(**(&&&instance))->field

Асоциирани методи

#[derive(Debug)]
struct User {
    username:      String,
    email:         String,
    sign_in_count: u64,
    active:        bool,
}

Асоциирани методи

impl User {
    fn new(username: &str, email: &str) -> User {
        User {
            username:      String::from(username),
            email:         String::from(email),
            sign_in_count: 0,
            active:        false,
        }
    }
}

fn main() {
    let gosho = User::new("~*-_Lo60-Go60_-*~", "go6enceto@abv.bg");
}

Съкратен синтаксис

impl User {
    fn new(username: String, email: String) -> User {
        User {
            username,
            email,
            sign_in_count: 0,
            active:        false,
        }
    }
}

Методи

тип Self

impl SomeLongStructNameThatWeDontWantToRepeat {
    fn new(username: String, email: String) -> Self {
        Self {
            username,
            email
        }
    }
}

Асоциирани методи

формално извикване на методи

fn main() {
    let r = Rectangle { length: 50, width: 30 };
    let area = Rectangle::area(&r);

    println!("Площта на правоъгълника е {}px²", area);
}

Въпроси