#function #rust #closures
#функция #Ржавчина #закрытие
Вопрос:
Я пытаюсь сделать что-то, что является нормальным на функциональном языке, т.Е. {F #, SML, OCaml, Haskel ..}, передавая функции в качестве ввода и вывода. Но я думаю, что я еще не закончил, когда дело доходит до системы типов Rust. Приведенный ниже код — это часть моего кода, которая выдает ошибку. Короче говоря, я создаю структуру, которая содержит функцию, которая что-то делает и возвращает какую-то другую вещь с возможной ошибкой. У функции or есть проблема, поскольку мне нужно включить, что мне когда-нибудь в будущем понадобится передать входные данные в функцию запуска, которую я использую closure. Я пытался использовать Fn в качестве типа, но компилятор все равно выдает ошибку.
pub struct Pattern<T>{
pat : fn(amp;str) -> Result<(T, amp;str),amp;'static str>
}
impl<T> Pattern<T> {
pub fn run(self, input: amp;str) -> Result<(T,amp; str), amp;'static str> {
(self.pat)(input)
}
pub fn or(self, pat: Pattern<T>) -> Pattern<T> {
Pattern {
pat: |input| match self.run(input) {
Ok(ret) => Ok(ret),
Err(msg) => {
match pat.run(input) {
Ok(ret) => Ok(ret),
Err(msg) => Err(msg),
}
}
}
}
}
}
Комментарии:
1. Похоже, что у вашего сокращенного кода есть еще одна проблема, в методе of вы используете переменные pat1 и pat2 , которые не определены.
2. небольшая опечатка, вызванная попыткой заставить ее работать. но это все еще не работает
Ответ №1:
Я не очень уверен в приведенном ниже решении, но кто знает…
Во-первых, or()
вы пытаетесь предоставить результирующее Pattern
закрытие захвата, где ожидается функция (без захвата); как вы указали в своем вопросе, Fn
признак кажется более подходящим для pat
члена. Чтобы фактически сохранить его, Box<dyn Fn( ...>
можно использовать.
Более того, run()
и or()
методы потребляют Pattern
s, поэтому каждый Pattern
можно использовать только один раз, что, вероятно, не то, что вы хотите. Я предлагаю вместо этого использовать ссылки.
Результирующий Pattern
in or
возвращается по значению (что, на мой взгляд, правильно); тогда все локальные переменные, которые необходимо захватить его замыканию ( self
и pat
параметры), должны быть move
объединены в замыкание.
Поскольку теперь у нас есть много Pattern
ссылок друг на друга, нам приходится явно иметь дело со временем жизни. Например, два Pattern
s, объединенные в or()
, должны пережить результирующий Pattern
. Эти ограничения распространяются по всему коду.
Наконец, была предпринята попытка проиллюстрировать использование в main()
.
(Возможно, более опытные программисты Rust найдут более простой способ добиться этого или некоторые ошибки)
pub struct Pattern<'p, T> {
pat: Box<dyn Fn(amp;str) -> Result<(T, amp;str), amp;'static str> 'p>,
}
impl<'p, T> Pattern<'p, T> {
pub fn run<'s>(
amp;self,
input: amp;'s str,
) -> Result<(T, amp;'s str), amp;'static str> {
(self.pat)(input)
}
pub fn or<'a, 'b>(
amp;'p self,
pat: amp;'a Pattern<T>,
) -> Pattern<'b, T>
where
'p: 'b,
'a: 'b,
{
Pattern {
pat: Box::new(move |input| match self.run(input) {
Ok(ret) => Ok(ret),
Err(_msg) => match pat.run(input) {
Ok(ret) => Ok(ret),
Err(msg) => Err(msg),
},
}),
}
}
}
fn main() {
let p1 = Pattern {
pat: Box::new(|input| {
if input.len() >= 4 {
Ok((1, amp;input[0..4]))
} else {
Err("too short for p1")
}
}),
};
let p2 = Pattern {
pat: Box::new(|input| {
if input.len() >= 2 {
Ok((2, amp;input[2..]))
} else {
Err("too short for p2")
}
}),
};
let p3 = p1.or(amp;p2);
println!("p1: {:?}", p1.run("a"));
println!("p2: {:?}", p2.run("a"));
println!("p3: {:?}", p3.run("a"));
println!("~~~~~~~~~~~~~~~~");
println!("p1: {:?}", p1.run("abc"));
println!("p2: {:?}", p2.run("abc"));
println!("p3: {:?}", p3.run("abc"));
println!("~~~~~~~~~~~~~~~~");
println!("p1: {:?}", p1.run("abcdef"));
println!("p2: {:?}", p2.run("abcdef"));
println!("p3: {:?}", p3.run("abcdef"));
/*
p1: Err("too short for p1")
p2: Err("too short for p2")
p3: Err("too short for p2")
~~~~~~~~~~~~~~~~
p1: Err("too short for p1")
p2: Ok((2, "c"))
p3: Ok((2, "c"))
~~~~~~~~~~~~~~~~
p1: Ok((1, "abcd"))
p2: Ok((2, "cdef"))
p3: Ok((1, "abcd"))
*/
}
Комментарии:
1. Он жалуется на то, что не может переместить self / pat в закрытие, потому что оно захвачено признаком Fn?
2. @kam Я только что попробовал еще раз с предоставленным кодом, и он не жалуется. Вы что-то изменили?
3. да, я не изменял функцию запуска, но это очень помогло: D