Указатель на функцию и объект Fn
fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { // definition
f(arg) + f(arg)
}
do_twice(|x| x + 1, 5) // call
Эта функция принимает как замыкания, так и указатели функций. Он принимает указатель на функцию в качестве типа параметра.
Когда я должен предпочесть это, используя объект-черту, например &dyn Fn(i32) -> i32
или же Box<dyn Fn(i32)-> i32>
вместо fn
fn do_twice(f: &dyn Fn(i32) -> i32, arg: i32) -> i32 { // definition
f(arg) + f(arg)
}
do_twice(&|x| x + 1, 5) // call
или же
fn do_twice(f: Box<dyn Fn(i32) -> i32>, arg: i32) -> i32 { // definition
f(arg) + f(arg)
}
2 ответа
fn
type - пустой указатель на функцию ( https://doc.rust-lang.org/std/primitive.fn.html).
Он не будет работать с замыканием, которое захватывает среду, и его нельзя реализовать вручную для вашего необычного типа (например, impl Fn for MySuperType
)
Так что единственная причина, по которой ваши примеры работают, это то, что они упрощены!
если вы сделаете это немного сложнее, произойдет сбой https://gist.github.com/rust-play/2167e73325daa1e2a179505209405917
Когда я должен предпочесть это, используя объект черты
Черты объектов не единственный другой вариант. Как отметил @DarthKotik, принимая fn
Указатель не разрешает замыкания, которые захватывают их окружение, но вы можете просто использовать параметр обычного типа, ограниченный Fn
принимать как функции, так и замыкания, без необходимости что-либо упаковывать:
fn do_twice<F>(f: F, arg: i32) -> i32
where
F: Fn(i32) -> i32
{
f(arg) + f(arg)
}
Или, что то же самое, но избегая дополнительной переменной типа:
fn do_twice(f: impl Fn(i32) -> i32, arg: i32) -> i32 {
f(arg) + f(arg)
}