Function pointers

I am trying to pass function pointers to structs and use them, but it is not working out. Here is the code I have:
`

mod sort;
use std::io::{self, Write};

struct Cacher<T>
  where T : Fn(u32) -> u32
{
    calculation: T,
    value: Option<u32>
}

impl <T> Cacher<T>
  where T:Fn(u32) ->u32
{
    fn new(calculation:T) -> Cacher<T> {
        Self {
            calculation,
            value: None,
        }
    }

    fn set_act(&mut self, func: T) {
        self.calculation = func;
    }

    fn fire(&mut self, x: u32) -> u32 {
        (self.calculation)(x)
    }

}

fn activation(i:u32) -> u32 {
    i
}
fn relu(i:u32) -> u32 {
    if i == 0 {
        return 1;
    }
    else {
        return i * 2;
    }
}

fn main() {
    let mut x = Cacher::new(activation);
    x.set_act(relu);
    println!("{}",x.fire(32));
    let x = 10;
}

I am receiving this error:
`

error[E0308]: mismatched types
  --> src/main.rs:45:15
   |
45 |     x.set_act(relu);
   |               ^^^^ expected fn item, found a different fn item
   |
   = note: expected type `fn(u32) -> u32 {activation}`
              found type `fn(u32) -> u32 {relu}`

`

Sorry that is not how the ReLU function looks like.

To allow optimization with monomorphized generics, each function has its own type (visible by the {activation} suffix there). When you create the cacher, Rust selects the concrete type as T.

You’ll need to “cast away” the concrete function type at least once, when creating the Cacher:

let x = Cacher::new(activation as fn(u32) -> u32)
let x = Cacher::new(activation as fn(_) -> _)  // should work too
// or
let x: Cacher<fn(u32) -> u32> = Cacher::new(activation)
1 Like

Okay after putting let mut x = Cacher::new(activation as Fn(u32) -> u32); I get error[E0620]: cast to unsized type: fn(u32) -> u32 {activation} as dyn std::ops::Fn(u32) -> u32

This works:
`

 fn main() {
    let mut x = Cacher::new(activation as fn(_) -> _);
    x.set_act(relu);
    println!("{}",x.fire(32));
    let x = 10;
}

It’s a fine difference between Fn and fn - the former is a trait implemented by functions (and closures), and the latter is a “simple” function pointer type.

4 Likes

If you only need to use function pointers, Cacher does not need to be generic because all function pointers with the same API have the same type, and functions like activation and relu will automatically coerce to a function pointer.

struct Cacher {
    calculation: fn(u32) -> u32,
    value: Option<u32>,
}

impl Cacher {
    fn new(calculation: fn(u32) -> u32) -> Self {
        Self {
            calculation,
            value: None,
        }
    }

    fn set_act(&mut self, func: fn(u32) -> u32) {
        self.calculation = func;
    }

    fn fire(&mut self, x: u32) -> u32 {
        (self.calculation)(x)
    }
}
3 Likes

I see, thanks.