format!
mod
, pub
, use
)
lib.rs
, main.rs
)
test
, derive
, cfg
)
enum IpAddrKind {
V4,
V6,
}
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
fn route(ip_type: IpAddrKind) { }
route(IpAddrKind::V4);
route(IpAddrKind::V6);
struct IpAddr {
kind: IpAddrKind,
address: String,
}
let home = IpAddr {
kind: IpAddrKind::V4,
address: String::from("127.0.0.1"),
};
let loopback = IpAddr {
kind: IpAddrKind::V6,
address: String::from("::1"),
};
По-удобен и четим начин
enum IpAddr {
V4(String),
V6(String),
}
let home = IpAddr::V4(String::from("127.0.0.1"));
let loopback = IpAddr::V6(String::from("::1"));
Може да спестим памет като знаем че IPv4
използва стойности от 0-255
enum IpAddr {
V4(u8, u8, u8, u8),
V6(String),
}
let home = IpAddr::V4(127, 0, 0, 1);
let loopback = IpAddr::V6(String::from("::1"));
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
struct QuitMessage; // unit struct
struct MoveMessage {
x: i32,
y: i32,
}
struct WriteMessage(String); // tuple struct
struct ChangeColorMessage(i32, i32, i32); // tuple struct
Variant | Discriminant | Data | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
no-mem | {unsigned} | 12 bytes | |||||||||||
Quit | 0 | ||||||||||||
Move | 1 | i32 | i32 | ||||||||||
Write | 2 | String | |||||||||||
ChangeColor | 3 | i32 | i32 | i32 |
impl Message {
fn call(&self) {
// ...
}
}
let m = Message::Write(String::from("hello"));
m.call();
Option има 2 стойности:
let some_number = Some(5);
let some_string = Some("string")
let absent_number: Option<i32> = None;
match
оператораmatch x {
Some(val) => println!("Value : {}", val),
None => println!("No value found"),
}
match
може да върне стойност:
let y = match x {
Some(val) => Some(val * val),
None => None,
};
match
може да върне стойност:
let y = match x {
Some(val) => val * val,
None => 0,
};
match
може да излезе от функцията
let y = match x {
Some(val) => val * val,
None => return None,
};
match
може да съдържа блокове от код:
let y = match x {
Some(val) => {
println!("Will return {}", val * val);
Some(val * val)
},
None => {
println!("Will do nothing!!");
None
},
};
Задължително трябва да се покрият всички случаи!
match x {
Some(i) => Some(i + 1),
}
error[E0004]: non-exhaustive patterns: `None` not covered --> | 6 | match x { | ^ pattern `None` not covered
Работи и с прости стойности:
'_' означава всичко останало
match x {
5 => println!("Five"),
_ => println!("Not five"),
}
Понякога да използваме match
за един случай и да покрием всички други с '_' е прекалено много код
let some_value = Some(0u8);
match some_value {
Some(3) => println!("three"),
_ => (),
}
Запознайте се с if let
:
let some_value = Some(0u8);
if let Some(3) = some_value {
println!("three");
}
let pair = (2, -2);
match pair {
(x, y) if x == y => println!("Едно и също"),
(x, y) if x + y == 0 => println!("Противоположни"),
(x, y) if x % 2 == 1 && y % 2 == 0 => println!("X е нечетно, Y е четно"),
(x, _) if x % 2 == 1 => println!("X е нечетно"),
_ => println!("Нищо интересно"),
}
let age: i32 = -5;
match age {
n if n < 0 => println!("Ще се родя след {} години.", n.abs()),
0 => println!("Новородено съм."),
1 ... 12 => println!("Аз съм лапе."),
13 ... 19 => println!("Аз съм тийн."),
_ => println!("Аз съм дърт."),
}
let age: i32 = -5;
match age {
n if n < 0 => println!("Ще се родя след {} години.", n.abs()),
0 => println!("Новородено съм."),
n @ 1 ... 12 => println!("Аз съм лапе на {}.", n),
n @ 13 ... 19 => println!("Аз съм тийн на {}.", n),
n => println!("Аз съм дърт, на {} съм вече.", n),
}
let score: u32 = 5;
match score {
0 | 1 => println!("слабичко :("),
_ => println!("стаа"),
}
struct User {
name: &'static str,
age: u8
}
let user = User {
name: "Пешо",
age: 12
};
match user {
User { name: "Пешо", age: _ } => println!("Ко стаа, Пешо"),
User { name: _, age: 12 } => println!("Ко стаа, лапе"),
User { name: x, .. } => println!("Ко стаа, {}", x),
_ => println!("Ко стаа")
}
#[derive(Debug)]
enum Token {
Text(String),
Number(f64)
}
let token = Token::Text(String::from("Отговора е 42"));
match token {
Token::Text(text) => println!("Токена е Text('{}')", text),
Token::Number(n) => println!("Токена е Number({})", n),
}
// компилационна грешка, ползваме moved value, заради match-ването на `text`
println!("В крайна сметка, токена е {:?}!", token);
Чрез `ref` стойността няма да се премести.
match token {
Token::Text(ref text) => println!("Токена е Text('{}')", text),
Token::Number(n) => println!("Токена е Number({})", n),
}
// няма грешка, `text` е взето като reference
println!("В крайна сметка, токена е {:?}!", token);
Какво всъщност прави ref?
Едно просто обяснение е чрез пример
let x = &1;
let ref y = 1;
&
в *дясната страна* на твърдението
ref
в *лявата страна* на твърдението
match
ръкава нямаме достъп до "дясната страна"Може би се досещате?
let mut token = Token::Text(String::from("Отговора е 42"));
match token {
Token::Text(ref mut text) => {
*text = String::from("Може би");
println!("Токена е Text('{}')", text)
},
Token::Number(n) => println!("Токена е Number({})", n),
}
let (mut a, b) = (1, 2);
let User { name: name, ..} = user;
let User { name, ..} = user;
let Some(val) = Some(5); // ??
let (a, b) = (b, a); // Please don't use this.. Use mem::swap instead.