Ще разгледаме част от домашното и как можете да го правите с итератори
За контекст така изглежда структурата Polynomial
pub struct Polynomial {
/// x^3 + 2*x^2 + 3
/// vec![1.0, 2.0, 0.0, 3.0]
coefs: Vec<f64>
}
impl Polynomial {
fn new() -> Self {
Self {
coefs: Vec::new()
}
}
}
fn mul(self, other: Self) -> Self::Output {
// Allocations can be optimized significantly
other.coefs.into_iter().rev().enumerate().fold(Polynomial::new(), |acc, (i, coef)| {
let base = self.clone();
base.coefs.resize(self.coefs.len() + i, 0.0);
acc + base * coef
})
}
fn add(self, other: Self) -> Self::Output {
if self.coefs.len() == 0 { return other; }
if other.coefs.len() == 0 { return self; }
let endless_zero = ::std::iter::repeat(0.0);
let rev_self = self.coefs.iter().rev();
let rev_other = other.coefs.iter().rev();
// Pad the coefs with 0s to align them
let mut coefs = if self.coefs.len() < other.coefs.len() {
rev_self.chain(endless_zero).zip(rev_other).map(|(x, y)| x + y).collect::<Vec<_>>()
} else {
rev_self.zip(rev_other.chain(endless_zero)).map(|(x, y)| x + y).collect::<Vec<_>>()
};
// Can't use rev on the map iterator since Chain is not ExactSizeIterator
// and Repeat is not a DoubleEndedIterator
coefs.reverse();
Polynomial::from(coefs)
}
pub fn interpolate(points: Vec<(f64, f64)>) -> Option<Self> {
// Skipping validations
// Split the points into `x` set and `y` set
let (xs, ys): (Vec<f64>, Vec<f64>) = points.into_iter().unzip();
// `zero` can be substituted by `new` for performance but this is closer to valid math
let poly = ys.into_iter().enumerate().fold(Polynomial::zero(), |acc, (i, y)| {
// Skip calculations when multiplication with 0 is expected
if y < ::std::f64::EPSILON {
return acc;
}
// Calculate Lagrange basis polynomial
let basis = xs.iter().enumerate().fold(Polynomial::one(), |acc, (j, x)| {
if i == j {
acc
} else {
// (x - xj) / (xi - xj)
acc * (Polynomial::from(vec![1.0, -x]) / (xs[i] - x))
}
});
acc + basis * y
});
Some(poly)
}
Знаем как се пишат функции
fn add_one (x: u32) -> u32 {
x + 1
}
Но какъв е типът на функция
let _: () = add_one;
fn(u32) -> u32 {main::add_one}
Какво се използва?
fn(u32) -> u32
*const ()
and usize
fn add_one (x: u32) -> u32 { x + 1 }
fn add_two (x: u32) -> u32 { x + 2 }
let mut f: fn(u32) -> u32 = add_one;
assert_eq!(f(1), 2);
f = add_two;
assert_eq!(f(1), 3);
fn add_one_v1 (x: u32) -> u32 { x + 1 }
let add_one_v2 = |x: u32| -> u32 { x + 1 };
let add_one_v3 = |x| { x + 1 };
let add_one_v4 = |x| x + 1 ;
Каква е разликата между функция и closure.
Closures могат да използват променливи дефинирани по-горе в scope-a.
fn main() {
let other = String::from("дядо"); // <-+
// |
Some("баба").map(|s| s.len() + other.len()); // --+
}
/// Структура в която запомняме променливите, които сме прихванали
struct State {
other: String,
}
impl State {
/// Функция която съдържа логиката
fn call(&self, s: &str) -> usize {
s.len() + self.other.len()
}
}
fn map_option(opt: Option<&str>, f: State) -> Option<usize> {
match opt {
Some(s) => Some(f.call(s)),
None => None,
}
}
fn main() {
let other = String::from("дядо");
map_option(Some("баба"), State { other });
}
Една подробност - closure-ите не консумират прихванатите променливи
let other = String::from("дядо");
println!("{}", Some("баба").map(|s| s.len() + other.len()));
println!("{}", other); // Ок
println!("{}", map_option(Some("баба"), State { other }));
println!("{}", other); // комп. грешка - use of moved value `other`
По подразбиране променливите се прихващат по референция
Можем да променим това с ключовата дума move
|s| s.len() + other.len();
// генерира
struct State<'a> {
other: &'a String
}
move |s| s.len() + other.len();
// генерира
struct State {
other: String
}
let other = String::from("дядо");
let closure = |s| s.len() + other.len();
Some("баба").map(closure);
let other = String::from("дядо");
let closure = State { other: &other };
struct State<'a> {
other: &'a String,
}
impl<'a> ??? for State<'a> {
fn call(self: ???, s: &str) -> usize {
s.len() + self.other.len()
}
}
Some("баба").map(closure);
Fn
FnMut
FnOnce
Синтаксис
Fn()
FnMut(u32, u32) -> bool
FnOnce() -> String
// опростено
trait FnOnce<Args> {
type Output;
fn call_once(self, args: Args) -> Self::Output;
}
self
// опростено
trait FnMut<Args>: FnOnce<Args> {
fn call_mut(&mut self, args: Args) -> Self::Output;
}
&mut self
// опростено
trait Fn<Args>: FnMut<Args> {
fn call(&self, args: Args) -> Self::Output;
}
&self
Когато създадем closure, компилатора имплементира всички trait-ове, който може
FnOnce
+ FnMut
+ Fn
FnOnce
+ FnMut
FnOnce
Fn
или FnMut
заради ограниченията на трейтовете
FnMut
и FnOnce
ако вече имате Fn
Да имплементираме Fn trait-овете за нашия тип State
error: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead
error: rust-call ABI is subject to change ... = help: add #![feature(unboxed_closures)] to the crate attributes to enable
error: use of unstable library feature 'fn_traits' ... = help: add #![feature(fn_traits)] to the crate attributes to enable
... или пък не
По-популярния начин за взимане на closure е чрез static dispatch
fn eval_and_increment<F>(f: F) -> usize where F: Fn_???() -> usize {
f() + 1
}
assert_eq!(eval_and_increment(|| 1), 2);
Кой Fn trait да сложим за ограничение?
FnOnce
- най-добре
FnMut
- ок
Fn
- в последен случай
fn eval_and_increment<F>(f: F) -> usize where F: FnOnce() -> usize {
f() + 1
}
assert_eq!(eval_and_increment(|| 1), 2);
Да си направим адаптор за итератор, който работи подобно на адаптора връщан от `Iterator::map()`
struct Map<I, F, B> where
I: Iterator,
F: FnMut(I::Item) -> B
{
iter: I,
f: F,
}
impl<I, F, B> Iterator for Map<I, F, B> where
I: Iterator,
F: FnMut(I::Item) -> B
{
type Item = B;
fn next(&mut self) -> Option<Self::Item> {
match self.iter.next() {
Some(item) => Some((self.f)(item)),
None => None,
}
}
}
// vec![1, 2, 3].into_iter().map(|x| x * 3)
let map = Map {
iter: vec![1, 2, 3].into_iter(),
f: |x| x * 3,
};
let v = map.collect::<Vec<_>>();
println!("{:?}", v);
[3, 6, 9]
fn get_incrementer() -> ??? {
|x| x + 1
}
Да проверим какъв е типът на closure-а
let _: () = |x| x + 1;
= note: expected type `()` found type `[closure@src/main.rs:2:17: 2:26]`
Тип генериран от компилатора, това не ни е полезно
Ако closure не прихваща променливи, той може автоматично да се сведе до указател към функция
fn get_incrementer() -> fn(i32) -> i32 {
|x| x + 1
}
Често се налага да прихванем променливи
fn curry(a: u32) -> ??? {
|b| a + b
}
Можем да използваме Trait objects
struct F<'a> {
closure: &'a Fn()
}
struct F {
closure: Box<Fn()>
}
Така дали ще е добре?
fn curry(a: u32) -> Box<Fn(u32) -> u32> {
Box::new(|b| a + b)
}
move
fn curry(a: u32) -> Box<Fn(u32) -> u32> {
Box::new(move |b| a + b)
}
assert_eq!(curry(1)(2), 3);
fn curry<'a>(a: &'a u32) -> Box<Fn(&u32) -> u32> {
Box::new(move |b| a + b)
}
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements ...
fn curry<'a>(a: &'a u32) -> Box<Fn(&u32) -> u32> {
struct State<'b> {
a: &'b u32
}
// impl Fn, FnMut, FnOnce for State
let state = State { a }; // State<'a>
Box::new(state) // очаква 'static
}
Какво означава обект (който не е референция) да има 'static
lifetime
Lifetime-а показва максимално ограничение до което може да живее обект
struct Foo<'a> { a: &'a i32 }
{
let a = 10; // ---+- 'a
// |
let foo = Foo { a: &a }; // ---+- foo: 'a
// |
} // <--+
Когато обект не държи референции няма такова ограничение
Затова се приема че обекта има 'static
lifetime
struct Foo { a: i32 }
{
let a = 10;
let foo = Foo { a: a }; // foo: 'static
}
По подразбиране се очаква trait object-а да няма такова ограничение
Box<Fn(&u32) -> u32>
-> Box<Fn(&u32) -> u32 + 'static>
Ако имаме ограничение трябва да го окажем изрично
fn curry<'a>(a: &'a u32) -> Box<Fn(&u32) -> u32 + 'a> {
Box::new(move |b| a + b)
}
assert_eq!(curry(&1)(&2), 3);
Нека опитаме да напишем прост event emitter със следните изисквания:
on
- регистрира слушател
off
- премахва слушател
emit
- излъчва съобщение с данниlet mut emitter = EventEmitter::new();
let _ = emitter.on("boot", |p: String| println!("{}", p));
let id = emitter.on("boot", |_| println!("hi"));
emitter.off(id);
emitter.emit("boot", "woot".to_string());
Ето как би изглеждала структурата
struct EventEmitter<E, P> {
map: HashMap<E, Vec<Box<Fn(P)>>>
}
Изглежда лесно...
Но нещата не са толкова прости
type Id = u64;
struct Listener<P> {
id: Id,
closure: Box<Fn(P) + 'static>
}
struct EventEmitter<E, P> where E: Eq + Hash, P: Clone {
next_id: Id,
map: HashMap<E, Vec<Listener<P>>>
}
impl<P> Listener<P> {
fn new<F>(id: Id, f: F) -> Self where F: Fn(P) + 'static {
Self {
id,
closure: Box::new(f)
}
}
}
impl<E, P> EventEmitter<E, P> where E: Eq + Hash, P: Clone {
fn new() -> Self {
Self {
next_id: Id::default(),
map: HashMap::new()
}
}
}
Място, където map::Entry
ще ни улесни
impl<E, P> EventEmitter<E, P> where E: Eq + Hash, P: Clone {
fn on<F>(&mut self, event: E, listener: F) -> Id where F: Fn(P) + 'static {
let id = self.next_id;
let listeners = self.map.entry(event).or_insert(Vec::new());
listeners.push(Listener::new(self.next_id, listener));
self.next_id += 1;
id
}
}
fn off(&mut self, id: Id) -> bool {
for (_, listeners) in self.map.iter_mut() {
let position = listeners.iter().position(|x| x.id == id);
if let Some(idx) = position {
listeners.remove(idx);
return true;
}
}
false
}
Ето една възможност да използваме Borrow
impl<E, P> EventEmitter<E, P> where E: Eq + Hash, P: Clone {
fn emit<B>(&self, event: B, payload: P) -> bool where B: Borrow<E> {
let event = event.borrow();
match self.map.get(event) {
Some(listeners) => {
// Клонираме данните, за да може да ги подадем на всички слушатели
listeners.iter().for_each(|f| (f.closure)(payload.clone()));
true
},
None => false
}
}
}