Skip to content

Search

Documentație

Function values

Passing functions around in Balaur Script: fn types, storing a function in a list, field or any, and working without closures.

Pe această pagină

A function is a value. Its name without a call gives the value, and fn(A, B) -> R is its type.

fn double(x: int) -> int { x * 2 }
fn square(x: int) -> int { x * x }
fn apply(f: fn(int) -> int, x: int) -> int { f(x) }

pub fn twice(k: int) -> int {
    let f = double;
    let g: fn(int) -> int = square;
    apply(f, k) + apply(g, k)
}

pub fn table(k: int) -> int {
    let fs = [double, square, double];
    let t = 0;
    for f in fs {
        t += f(k);
    }
    t
}

// twice(5) == 35
// table(3) == 21

Storing one

A function value goes in a local, a list, a map, a field or an any. A call goes through a local, so take the value out first.

fn square(x: int) -> int { x * x }

pub class Picker { pick: fn(int) -> int }

impl Picker {
    pub fn run(x: int) -> int {
        let f = self.pick;
        f(x)
    }
}

pub fn picked(k: int) -> int {
    let p = Picker { pick: square };
    p.run(k)
}

pub fn from_map() -> int {
    let named: {str: fn(int) -> int} = { "sq": square };
    let f = named["sq"].unwrap();
    f(3)
}

pub fn from_any() -> int {
    let v: any = { "f": square };
    let f: fn(int) -> int = v["f"];
    f(4)
}

// picked(6) == 36
// from_map() == 9
// from_any() == 16

No closures

A function value names a function, and nothing more. It captures no variables, since there are no closures. Where a callback needs state, pass the state in, as the second function here does:

struct Tally { sum: int }

fn add(t: &mut Tally, n: int) { t.sum += n; }

fn each(xs: [int], t: &mut Tally, f: fn(&mut Tally, int)) {
    for x in xs {
        f(t, x);
    }
}

pub fn run() -> int {
    let t = Tally { sum: 0 };
    each([1, 2, 3], t, add);
    t.sum
}

// run() == 6

The engine calls back by name instead: a listener names a method.

What is a value

Only a plain function of the script is. A method, an engine function and an async fn are not, and the types must match exactly.

pub class S { x: int }
impl S { fn m() -> int { 1 } }
fn one() -> int { 1 }
async fn wait_a_bit() -> int { 1 }

pub fn method() -> int { let g = S.m; 1 }
pub fn not_a_function(x: int) -> int { x(1) }
pub fn wrong_type() -> int { let g: fn(int) -> int = one; 1 }
pub fn async_one() -> int { let g = wait_a_bit; 1 }

// error: 6:34: unknown name `S`
// error: 7:40: `x` is a int, not a function
// error: 8:54: expected fn(int) -> int, got fn() -> int
// error: 9:37: only a script's own plain function can be a `fn` value; `wait_a_bit` is not one