
Взлом умной секс-игрушки. В плане безопасности состояние катастрофическое. Ну и вообще, зачем данные между плагом и PC гонять в виде JSON?!
youtube.com/watch?v=RnxcPeemHSc
habr.com/ru/company/ua-hosting/blog/495378
Size: a a a
// vvvvvvvvvvvvvv - это же функция, верно?Попробуем её применить:
fn apply(func: fn(u32) -> u32, x: u32) -> u32 {
func(x)
}
fn add_one(x: u32) -> u32 {Этот код выводит "4", как и ожидается. Но постойте-ка, у нас же есть замечательный синтаксис для лямбда-функций! Может, применить его?
x + 1
}
fn main() {
println!("{}", apply(add_one, 3));
}
fn main() {Этот код тоже выводит "4". Что ж, давайте немного усложним код:
println!("{}", apply(|x| x + 1, 3));
}
fn main() {И этот код выводит... А не, не выводит, он не компилируется:
let one = 1;
println!("{}", apply(|x| x + one, 3));
}
error[E0308]: mismatched typesНо ведь это же функция!
--> src/main.rs:8:26
|
8 | println!("{}", apply(|x| x + one, 3));
| ^^^^^^^^^^^ expected fn pointer, found closure
|
= note: expected fn pointer `fn(u32) -> u32`
found closure `[closure@src/main.rs:8:26: 8:37 one:_]`
one
. Тип же fn(u32) -> u32
— это функциональный указатель (function pointer), фактически, просто адрес в памяти, по которому располагается код функции. Неудивительно, что apply
не удалось вызвать — это разные типы с разными размерами!apply
с аргументом |x| x + 1
?|x| x + 1
не захватывает никаких переменных из окружения, а такие замыкания могут быть приведены к функциональному указателю начиная с версии Rust 1.19. Такое приведение может сработать в ряде различных мест, в число которых входит и аргумент функции при вызове.apply
с |x| x + one
?apply
. Мы не можем дать типу замыканию имя, поэтому правильным решением будет сделать apply
обобщённой функцией:fn apply<F>(func: F, x: u32) -> u32Что тут происходит? Мы ввели обобщённый параметр
where
F: Fn(u32) -> u32,
{
func(x)
}
F
и добавили на него ограничение Fn(u32) -> u32
. Это означает, что значение типа F
можно вызвать как функцию с одним аргументом u32
, причём неограниченное число раз. Теперь apply
можно вызвать в любом варианте:fn main() {Отлично! Значит, замыкания имеют разные типы, а у обычных функций с одинаковыми сигнатурами типы одинаковые
println!("{}", apply(add_one, 3));
println!("{}", apply(|x| x + 1, 3));
let one = 1;
println!("{}", apply(|x| x + one, 3));
}
type Pair<T> = (T, T);Этот код не компилируется:
fn add_one(x: u32) -> u32 {
x + 1
}
fn add_two(x: u32) -> u32 {
x + 2
}
fn main() {
let funcs: Pair<_> = (add_one, add_two);
}
error[E0308]: mismatched types
--> src/main.rs:12:36
|
12 | let funcs: Pair<_> = (add_one, add_two);
| ^^^^^^^ expected fn item, found a different fn item
|
= note: expected fn item `fn(_) -> _ {add_one}`
found fn item `fn(_) -> _ {add_two}`