Указатель на функцию и объект 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)
}
Другие вопросы по тегам