2014-12-05 125 views
3

我想要使用for循环遍历函数的向量并在每个步骤执行每个函数。遍历函数的向量

fn f1(i: i32) -> i32 { 
    i * 2 
} 

fn f2(i: i32) -> i32 { 
    i * 4 
} 

fn main() { 
    let mut arr: Vec<|i32| -> i32> = Vec::new(); 
    arr.push(f1); 
    arr.push(f2); 

    for f in arr.iter() { 
     println!("{}", f(1)); 
    } 
} 

f(1)已尝试执行给出了这样的错误:

error: expected function, found '&|i32| -> i32' 

我把功能载体猜测他们的类型发生突变,不再像一个正常功能。有没有办法将它改回来,还是我错过了什么?

+0

您能给出一个最小可重现的例子吗?什么是'f1'和'f2'? – 2014-12-05 09:12:53

+0

http://stackoverflow.com/questions/26301269/calling-closures-from-an-array-in-rust,但其答案不再有效(可能在关闭改革后)。 – 2014-12-05 09:13:12

+0

@MatthieuM。编辑 – AllTheTime 2014-12-05 09:17:34

回答

8

已更新为Rust 1.x,答案的旧版本仍保留在编辑历史记录中。

从Rust 1.x开始,unboxed closures是语言中唯一的闭包,它们不需要再添加功能标记。而且,静态函数可以很容易地转换为无箱闭包。因此,调用函数从功能的载体正确的方法是:

fn f1(i: i32) -> i32 { i * 2 } 

fn f2(i: i32) -> i32 { i * 4 } 

fn main() { 
    let p1 = &f1; 
    let p2 = &f2; 
    let mut arr: Vec<&Fn(i32) -> i32> = Vec::new(); 
    arr.push(p1); 
    arr.push(p2); 

    for f in &arr { 
     println!("{}", (*f)(1)); 
    } 
} 

有与旧版本相同的代码的一些差异,最显着之处在于p1p2被矢量之前定义。这是必要的,因为否则它可能暂时包含对已销毁对象的引用。

这里我已经使用了Fn()闭包,它可以通过共享引用访问它的环境,所以通过引用迭代向量就足够了。如果我已经使用了FnMut()闭包,我将不得不使用可变引用的迭代,类似的情况适用于FnOnce()并按值重复(尽管我认为在后一种情况下不可能使用FnOnce(),因为您可以' t存储没有装箱的特质对象,并且Box<FnOnce()>现在不能被调用,需要像FnBox()这样的解决方法)。

或者,如果你知道你只有静态功能的工作,有可能指针直接对它们进行存储,而无需使用封闭性状:

fn f1(i: i32) -> i32 { i * 2 } 

fn f2(i: i32) -> i32 { i * 4 } 

fn main() { 
    let mut arr: Vec<fn(i32) -> i32> = Vec::new(); 
    arr.push(f1); 
    arr.push(f2); 

    for f in &arr { 
     println!("{}", (*f)(1)); 
    } 
} 

虽然f1f2实际上有不同的不兼容的类型,他们在适当的上下文中使用时会自动强制为通用函数指针类型fn(i32) -> i32,如上例所示。

因为静态函数没有任何环境,所以可以自由地克隆对它们的引用并通过任何引用来调用它们。如果你只需要静态函数,这大概是的方法。

+0

你能稍微解释一下,如何用'(* f)'推迟值使它可用吗? – AllTheTime 2014-12-05 09:24:18

+0

没有办法在封闭签名中指明它不会改变其环境吗? – 2014-12-05 09:27:27

+0

@AllTheTime,'f'是'&mut | i32 | - > i32',所以得到'| i32 | - > i32',你必须解引用它,就像当你需要从'&int'获得'int'一样。 – 2014-12-05 09:28:48