![](/img/trans.png)
[英]How can I pass a FnMut closure to a function using a reference in Rust?
[英]How can I implement Y-Combinator with FnMut in Rust?
我找到了一個支持 Fn 的 Y-Combinator 的實現。 但是我想要一個 FnMut 版本。
但是, FnMut 不能包裝到Rc
中,所以我將它們包裝在Rc<RefCell>
中。 以下代碼可以遞歸方式使a[i] = i
。 這是我發現的最簡單的代碼,用於測試我們是否可以在閉包中調用自身。
// test code part
let mut a = vec![0; 5];
let n = a.len();
y_mut(Rc::new(RefCell::new(|f: Rc<RefCell<dyn FnMut(usize)>>| {
move |i| {
if i < n {
a[i] = i;
((*f).borrow_mut())(i + 1);
}
}
})))(0);
println!("a is {:?}", a);
這是我的y_mut
版本,源自演示。
fn y_mut<A, O, F>(f: Rc<RefCell<dyn FnMut(Rc<RefCell<dyn FnMut(A) -> O>>) -> F>>) -> impl FnMut(A) -> O
where
F: FnMut(A) -> O,
F: 'static,
A: 'static,
O: 'static,
{
struct X<F>(Rc<RefCell<dyn FnMut(X<F>) -> F>>);
impl<F> Clone for X<F> {
fn clone(&self) -> Self {
Self(Rc::clone(&self.0))
}
}
impl<F> X<F> {
fn call(&self, x: Self) -> F {
((*self.0).borrow_mut())(x)
}
}
let f = Rc::new(RefCell::new(move |x: X<F>| {
let mut ff = (*f).borrow_mut();
ff(Rc::new(RefCell::new(move |a| (x.call(x.clone()))(a))))
}));
let x = X(f);
(|x: X<F>| x.call(x.clone()))(x)
}
但是,此代碼無法編譯,因為|f: Rc<RefCell<dyn FnMut(usize)>>|
只實現 FnOnce,而不是 FnMut。 我想知道如何解決這個問題?
測試代碼閉包中的move
使其也移動a
閉包中。 您可以a
引用向量並移動它來防止這種情況:
y_mut(Rc::new(RefCell::new(|f: Rc<RefCell<dyn FnMut(usize)>>| {
let a = &mut a;
move |i| {
...
}
})))(0);
但隨后閉包不再滿足'static
界限,因為它現在從其環境中借用了一些東西。 您可以通過使用另一個Rc
來解決這個問題,並將其克隆到外部和內部閉包中。 此版本的測試代碼編譯:
fn main() {
let a = Rc::new(RefCell::new(vec![0; 5]));
let n = a.borrow().len();
y_mut(Rc::new(RefCell::new({
let a = Rc::clone(&a);
move |f: Rc<RefCell<dyn FnMut(usize)>>| {
let a = Rc::clone(&a);
move |i| {
if i < n {
a.borrow_mut()[i] = i;
f.borrow_mut()(i + 1);
}
}
}
})))(0);
println!("a is {:?}", a.borrow());
}
當然,這樣做意味着您不需要FnMut
開始,因此 Y 組合器實現可以簡化回您開始時的非 mut 版本。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.