2013-10-15 1 views
2

Это короткий пример по этому вопросу.Как сделать замыкание «extern» C «fn»

#[fixed_stack_segment] 
fn test(func: extern "C" fn() -> ~str) -> ~str { 
    func() 
} 
extern "C" fn func1() -> ~str { 
    ~"hello" 
} 

fn main() { 
    let func2 = || -> ~str { ~"world" }; 
    println(test(func1)); 
    println(test(func2)); 
} 

Затем rustc останавливается с ошибкой.

st.rs:13:17: 13:22 error: mismatched types: expected `extern "C" fn() -> ~str` but found `&fn<no-bounds>() -> ~str` (expected extern fn but found fn) 
st.rs:13  println(test(func2)); 

Я не могу найти способ сделать лямбду наружу fn.

Что мне делать?

+2

Я не думаю, что вы можете, потому что закрытие подразумевает захваченную среду, а внешние функции не имеют среды. Однако я не уверен, давайте подождем более авторитетный ответ. –

ответ

2

Синтаксис закрытия всегда либо &fn или ~fn и сделать extern "ABI" fn (для любого значения ABI, в том числе Rust), необходимо использовать полную декларацию функции.

#[fixed_stack_segment] 
fn test(func: extern "C" fn() -> ~str) -> ~str { 
    func() 
} 
extern "C" fn func1() -> ~str { 
    ~"hello" 
} 

fn main() { 
    extern "C" fn func2() -> ~str { ~"world" } 

    println(test(func1)); 
    println(test(func2)); 
} 

Существует несколько притчи позволяет лямбде создавать не-закрытия тоже с ABI вывода, как и все остальное в сигнатуре типа, но это еще не реализован.


Однако, как говорит Владимир Матвеев, существует фундаментальное различие между закрытием и нормальными функциями, что означает, что один никогда не будет в состоянии использовать все возможности закрытия при передаче в качестве extern fn. Разница заключается в том замыкание может захватить (ссылки на) переменном, т.е.

let n = 1; 
let f = || { n + 1 }; 

Это означает замыкание эффективно представлено

struct AndFn { // &fn 
    env: &Environment, 
    func: extern "Rust" fn() 
} 

struct TwiddleFn { // ~fn 
    env: ~Environment, 
    func: extern "Rust" fn() 
} 

где Environment это структура, которая содержит все переменный захват для этого закрытия (он различается для каждого &fn, так как каждый захватывает разные вещи); func - это указатель функции на код замыкания, который запускается при вызове замыкания; если замыкание фиксирует любые переменные, func будет требовать существования env. Таким образом, синтаксис лямбда будет иметь возможность создавать простые extern fn с, когда он не фиксирует никаких переменных.

+0

Хмм ..., я попытался использовать [rust-mozjs] (https://github.com/mozilla-servo/rust-mozjs) и хочу обернуть JSFuntionSpec (для этого требуется «extern» C «fn»). Спасибо! Я собираюсь найти другой путь. –