Второ домашно! Отложено до понеделник!
FromStr
и parse
Result
try!
и по-удобния му вариант ?
fn main() {
let b = Box::new(5);
println!("b = {}", b);
}
5
fn main() {
let x = Box::new(3);
let y = Box::new(5);
println!("{}", x + y);
}
error[E0369]: binary operation `+` cannot be applied to type `std::boxed::Box<{integer}>` --> src/main.rs:5:23 | 5 | println!("{:#?}", x + y); | ^^^^^ | = note: an implementation of `std::ops::Add` might be missing for `std::boxed::Box<{integer}>`
fn main() {
let x = Box::new(3);
let y = Box::new(5);
println!("{}", *x + *y);
}
8
use std::mem::size_of_val;
fn main() {
let v = vec!["baba", "dyado"];
println!("v = {:?}", v);
println!("size(v) = {:?}", size_of_val(&v));
println!("-----------------------------");
let bv = Box::new(vec!["baba", "dyado"]);
println!("bv = {:?}", bv);
println!("size(bv) = {:?}", size_of_val(&bv));
println!("size(*bv) = {:?}", size_of_val(&*bv));
}
v = ["baba", "dyado"] size(v) = 24 ----------------------------- bv = ["baba", "dyado"] size(bv) = 8 size(*bv) = 24
А за какво ни е всъщност?
#[derive(Debug)]
enum List {
Nil,
Cons(i32, List),
}
use List::{Cons, Nil};
fn main() {
let list = Cons(1, Cons(2, Cons(3, Nil)));
println!("{:#?}", list);
}
error[E0072]: recursive type `List` has infinite size --> src/main.rs:2:1 | 2 | enum List { | ^^^^^^^^^ recursive type has infinite size 3 | Nil, 4 | Cons(i32, List), | ----- recursive without indirection | = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `List` representable
#[derive(Debug)]
enum List {
Nil,
Cons(i32, Box<List>),
}
use List::{Cons, Nil};
fn main() {
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
println!("{:?}", list);
}
Cons(1, Cons(2, Cons(3, Nil)))
fn vec_of_things<'a>() -> Vec<&'a Display> {
let x = 123;
vec![&x, &3.14, &"foobar"] // грешка при компилация
}
fn vec_of_things() -> Vec<Box<Display>> {
let x = 123;
vec![Box::new(x), Box::new(3.14), Box::new("foobar")] // ok
}
Box<Error>
- ако ни мързи да правим error handling
fn get_x() -> Result<i32, io::Error> { ... }
fn get_y() -> Result<i32, fmt::Error> { ... }
fn foo() -> Result<i32, Box<error::Error>> {
let x = get_x()?;
let y = get_y()?;
Ok(x + y)
}
rustup install nightly
rustup run nightly cargo run
Има специален keyword : `box` за създаване на Box smart pointer-и
let x = Box::new(5);
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
// Може да се напише така:
let x = box 5;
let list = Cons(1, box Cons(2, box Cons(3, box Nil)));
За да може да използвате този 'feature', трябва да го оповестите така в началото на програмата си:
#![feature(box_syntax)]
enum Fruit {
Apple,
Orange,
Tomato,
Cherry
}
fn main() {
let apple_in_a_box = box Fruit::Apple;
}
Ключовата дума `box` е мнооого полезна при pattern matching! Пример:
#[derive(Clone, Debug, PartialEq)]
pub enum Term {
True,
False,
If(Box<Term>, Box<Term>, Box<Term>),
Value
}
fn one_step_eval(t: Term) -> Result<Term, String> {
match t {
If(t1, t2, t3) => {
match *t1 { // След малко ще си говорим за Deref, спокойно!
True => Ok(*t2),
False => Ok(*t3),
_ => Ok(If(Box::new(one_step_eval(*t1)?), t2, t3)),
}
},
any => Err(format!("Term can't be evaluated : {:?}", any))
}
}
Ключовата дума `box` е мнооого полезна при pattern matching! Пример:
fn one_step_eval(t: Term) -> Result<Term, String> {
match t {
If(box True, t2, _) => Ok(*t2),
If(box False, _, t3) => Ok(*t3),
If(t1, t2, t3) => Ok(If(box one_step_eval(*t1)?), t2, t3),
any => Err(format!("Term can't be evaluated : {:?}", any))
}
}
За да може да използвате този 'feature', трябва да го оповестите така в началото на програмата си:
#![feature(box_patterns)]
let mut x = 5;
{
let y = &mut x;
*y += 1
}
pub trait Deref {
type Target: ?Sized;
fn deref(&self) -> &Self::Target;
}
Sized
е магически trait
u8
, Vec<T>
, &T
Sized
: [T]
, Trait
&[T]
, Box<[T]>
, &Trait
, Box<Trait>
?Sized
означава, че типа не е нужно да имплементира Sized.
fn foo<T>() {} // Използваем само с тип, който имплементира Sized
fn bar<T: ?Sized>() {} // Използваем с тип, който *може* да имплементира Sized, но не е *нужно*
Особено ограничение, понеже разширява броя типове, които могат да се приемат, вместо да го стеснява.
use std::ops::Deref;
struct Mp3 {
audio: Vec<u8>,
artist: Option<String>,
title: Option<String>,
}
impl Deref for Mp3 {
type Target = Vec<u8>;
fn deref(&self) -> &Vec<u8> {
&self.audio
}
}
fn main() {
let my_favorite_song = Mp3 {
audio: vec![1, 2, 3],
artist: Some(String::from("Poets of the Fall")),
title: Some(String::from("Carnival of Rust")),
};
assert_eq!(vec![1, 2, 3], *my_favorite_song);
}
*my_favorite_song
*(my_favorite_song.deref())
fn deref(&self) -> &Vec<u8> {
&self.audio
}
*(&my_favorite_song.audio)
fn compress_mp3(audio: &[u8]) -> Vec<u8> {
// ...
}
compress_mp3(my_favorite_song.audio.as_slice()
&[u32; 5]
→ &[u32]
&Vec<u32>
→ &[u32]
&String
→ &str
fn compress_mp3(audio: &[u8]) -> Vec<u8> {
// ...
}
compress_mp3(my_favorite_song.audio.as_slice())
// &Vec<u8> -> &[u8]
compress_mp3(&my_favorite_song.audio)
// &Mp3 -> &Vec<u8>
compress_mp3(&my_favorite_song)
&T
до &U
когато T: Deref<Target=U>
&mut T
до &mut U
когато T: DerefMut<Target=U>
&mut T
до &U
когато T: Deref<Target=U>
Deref
се ползва *специфично* за smart pointer-и.
Mp3
е симпатичен пример, но автоматичен дереф може да е доста объркващ в случай на грешка.use std::rc::Rc;
fn main() {
let first = Rc::new(String::from("foobar"));
let second = Rc::clone(&first);
println!("{}", first);
println!("{}", second);
}
foobar foobar
let a = Rc::new(3);
let b = Rc::new(5);
println!("{}", *a + *b);
let mut a = Rc::new(3);
*a = 5;
println!("{:?}", a);
error[E0594]: cannot assign to immutable borrowed content --> src/main.rs:6:5 | 6 | *a = 5; | ^^^^^^ cannot borrow as mutable
Rc
не ни позволява да взимаме mutable reference към пазената стойност
&mut T
/ много &T
use std::rc::Rc;
fn main() {
let mut a = Rc::new(3);
*Rc::make_mut(&mut a) = 5;
println!("a: {}", a);
}
a: 5
use std::rc::Rc;
fn main() {
let mut a = Rc::new(3);
let b = Rc::clone(&a);
*Rc::make_mut(&mut a) = 5;
println!("a: {}", a);
println!("b: {}", b);
}
a: 5 b: 3
impl<T> Rc<T> where T: Clone {
fn make_mut(this: &mut Rc<T>) -> &mut T
}
use std::cell::Cell;
fn main() {
// забележете, че няма `mut`
let cell = Cell::new(10);
println!("{}", cell.get());
cell.set(42);
println!("{}", cell.get());
}
10 42
Copy
типове
get
прави копие на пазената стойност
set
презаписва пазената стойност с новата
&
/&mut
) към стойносттаuse std::cell::RefCell;
fn main() {
let cell = RefCell::new(String::from("foo")); // отново няма `mut`
println!("{}", cell.borrow());
{
let mut r = cell.borrow_mut();
r.push_str("bar");
}
println!("{}", cell.borrow());
}
foo foobar
borrow()
ще върне структура, която има deref до &T
borrow_mut()
ще върне структура, която има deref до &mut T
panic!
Често `Cell` и `RefCell` се използват в комбинация с `Rc`
use std::cell::RefCell;
use std::rc::Rc;
fn main() {
let first = Rc::new(RefCell::new(String::from("foo")));
let second = Rc::clone(&first);
first.borrow_mut().push_str("bar");
println!("{}", second.borrow());
}
foobar
struct TreeNode {
index: u32,
parent: Option<Rc<RefCell<TreeNode>>>,
children: Vec<Rc<RefCell<TreeNode>>>,
}
impl TreeNode {
fn new(index: u32, parent: Option<Rc<RefCell<TreeNode>>>) -> Rc<RefCell<TreeNode>> {
Rc::new(RefCell::new(TreeNode { index, parent, children: vec![] }))
}
}
fn make_tree() -> Rc<RefCell<TreeNode>> {
let root = TreeNode::new(0, None);
let v1 = TreeNode::new(1, Some(Rc::clone(&root)));
let v2 = TreeNode::new(2, Some(Rc::clone(&root)));
{
let mut r = root.borrow_mut();
r.children.push(v1);
r.children.push(v2);
}
root
}
let tree = make_tree();
mem::drop(tree); // ?
mem::forget
Да се върнем на проблема с дървото
use std::mem;
use std::rc::{Rc, Weak};
fn main() {
let rc = Rc::new(10);
let weak = Rc::downgrade(&rc);
println!("{:?}", weak.upgrade());
mem::drop(rc);
println!("{:?}", weak.upgrade());
}
Some(10) None