【问题标题】:Rust closure and fn mismatchRust 闭包和 fn 不匹配
【发布时间】:2020-12-30 13:55:21
【问题描述】:

我正在尝试在函数式语言中做一些正常的事情,即 {F#, SML, OCaml, Haskel..} 将函数作为输入和输出传递。 但我认为在 Rust 类型系统方面我还没有退出。下面的代码是我的代码中出错的部分。简而言之,我正在制作一个包含一个函数的结构,它会做一些事情并返回一些可能出现错误的其他事情。 or 函数有问题,因为我需要在将来的某个时间将输入传递给我正在使用闭包的 run 函数。我已经尝试使用 Fn 作为类型,但它仍然使编译器出错。

pub struct Pattern<T>{
   pat : fn(&str) -> Result<(T, &str),&'static str>
}

impl<T> Pattern<T> {
    pub fn run(self, input: &str) -> Result<(T,& str), &'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),
                    } 
                }
            }
        }  
    }
}

【问题讨论】:

  • 看起来您的代码被截断了另一个问题,在 of 方法中,您使用的是未定义的 pat1pat2 变量.
  • 试图让它工作的小错字。但是还是不行

标签: function rust closures


【解决方案1】:

我对下面的解决方案不是特别有信心,但谁知道...

首先,在or() 中,您尝试提供生成的Pattern 捕获 期望函数(无捕获)的闭包;正如你所说 在您的问题中,Fn 特征似乎更适合 pat 成员。 为了实际存储,可以使用Box&lt;dyn Fn( ...&gt;

此外,run()or() 方法使用 Patterns,因此 每个Pattern 只能使用一次,这可能不是您想要的。 我建议改用引用。

or 中的结果 Pattern 按值返回(这是正确的, 在我看来);然后它的闭包需要捕获的所有局部变量 (selfpat 参数)必须是 moved 进入闭包。

由于我们现在有很多Patterns 相互引用, 我们必须明确地处理生命周期。比如两个Patterns 结合在or() 中必须比生成的Pattern 寿命更长。 这些约束在整个代码中传播。

最后尝试说明main()中的用法。

(可能更有经验的 Rust 程序员会发现一个更简单的 实现这一点的方法,或一些错误)

pub struct Pattern<'p, T> {
    pat: Box<dyn Fn(&str) -> Result<(T, &str), &'static str> + 'p>,
}

impl<'p, T> Pattern<'p, T> {
    pub fn run<'s>(
        &self,
        input: &'s str,
    ) -> Result<(T, &'s str), &'static str> {
        (self.pat)(input)
    }

    pub fn or<'a, 'b>(
        &'p self,
        pat: &'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, &input[0..4]))
            } else {
                Err("too short for p1")
            }
        }),
    };
    let p2 = Pattern {
        pat: Box::new(|input| {
            if input.len() >= 2 {
                Ok((2, &input[2..]))
            } else {
                Err("too short for p2")
            }
        }),
    };
    let p3 = p1.or(&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"))
    */
}

【讨论】:

  • 它抱怨它无法将 self/pat 移动到闭包中,因为它被 Fn 特征捕获?
  • @kam 我刚刚用提供的代码再次尝试,它没有抱怨。你有什么改变吗?
  • 是的,我没有改变运行功能,但这有很大帮助:D
猜你喜欢
  • 2018-01-16
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
  • 2022-09-24
  • 2015-07-22
  • 1970-01-01
  • 2021-08-19
相关资源
最近更新 更多