@ Лукас Калбертодт приводит более простой пример, который я буду использовать в качестве основы для объяснения:
fn foo<F: Fn()>(x: bool, _: F) {
if x {
foo(false, || {}) // line 3
}
}
fn main() {
foo(true, || {}); // line 8
}
Важным моментом здесь является то, что каждое замыкание имеет уникальный тип, поэтому давайте создадим экземпляр этой программы:
- 1-е закрытие, в
main
, назовем тип main#8
. - 1-е создание
foo
, в main
, foo<[main#8]>
. - 2-е закрытие, в
foo
, назовем тип {foo<[main#8]>}#3
. - 2-е создание
foo
, в foo
, foo<[{foo<[main#8]>}#3]>
. - 3-е закрытие, в
foo
, назовем тип {foo<[{foo<[main#8]>}#3]>}#3
. - 3-й экземпляр
foo
, в foo
, foo<[{foo<[{foo<[main#8]>}#3]>}#3]>
. - ...
Каждый новый экземпляр foo
создает новый тип замыкания, каждый новый тип замыкания создает новый экземпляр foo
, это рекурсия без базового случая: переполнение стека .
Вы можете решить проблему, НЕ создавая замыкание при рекурсивном вызове preorder_traverse
:
- , либо используя стирание типа, хотя время выполнения большеhead,
- или просто с помощью отдельной внутренней функции для рекурсии, поскольку она не зависит от
F
.
Пример:
fn preorder_traverse_impl(
root: Option<&Rc<RefCell<TreeNode>>>,
parent_value: i32,
predict: fn(i32, i32) -> bool
)
-> bool
{
if let Some(node) = root {
let root_val = root.as_ref().unwrap().borrow().val;
if !predict(root_val, parent_value) {
return false;
}
preorder_traverse_impl(node.borrow().left.as_ref(), root_val, lessThan)
&& preorder_traverse_impl(node.borrow().right.as_ref(), root_val, greaterThan)
} else {
true
}
}
fn preorder_traverse<F: Fn(i32) -> bool>(root: Option<&Rc<RefCell<TreeNode>>>, predict: F) -> bool {
if let Some(node) = root {
let root_val = root.as_ref().unwrap().borrow().val;
if !predict(root_val) {
return false;
}
preorder_traverse_impl(node.borrow().left.as_ref(), root_val, lessThan)
&& preorder_traverse_impl(node.borrow().right.as_ref(), root_val, greaterThan)
} else {
true
}
}
На ночнойтакже может создать тип предиката и реализовать для него Fn
(LessThan<i32>
и GreaterThan<i32>
).