从if语句中分配一个未装箱的闭包

时间:2015-01-11 18:15:57

标签: types closures rust

我正在尝试更新Rust 1.0.alpha的代码,而我遇到问题的一个部分可以简化为以下示例。我已经注释了闭包类型,并切换到了未装箱的闭包。但是,我无法找到正确的类型以获得乐趣。我试过fun : FnMut() -> IoResult<u32>,但即使FnMut,FnOnce和朋友的全部观点都是为了实现封闭提供特征;编译器似乎无法正确匹配类型。

我已阅读以下内容:

但他们没有明确解释如何处理这个问题

use std::io::File;
use std::io::IoResult;
use std::io::fs::PathExtensions;
use std::iter::range_step;

fn main() {
    let path = Path::new("fid");
    let mut file = File::open(&path);
    let big = true;
    let mut v = vec![];
    let fun = if big {
        |&mut:| file.read_be_u32()
    } else {
        |&mut:| file.read_le_u32()
    };
    for _ in range_step(0u64, path.stat().unwrap().size,4u64){
        v.push(fun().unwrap());
    }
    println!("{}",v);
}

这给出了:

scratch.rs:11:15: 15:6 error: if and else have incompatible types: expected `closure[scratch.rs:12:9: 12:35]`, found `closure[scratch.rs:14:9: 14:35]` (expected closure, found a different closure)

并使用fun : FnMut() -> IoResult<u32>fun : FnMut<(),IoResult<u32>>提供:

scratch.rs:12:9: 12:35 error: mismatched types: expected `core::ops::FnMut() -> core::result::Result<u32, std::io::IoError>`, found `closure[scratch.rs:12:9: 12:35]` (expected trait core::ops::FnMut, found closure)
scratch.rs:12         |&mut:| file.read_be_u32()
                      ^~~~~~~~~~~~~~~~~~~~~~~~~~
scratch.rs:14:9: 14:35 error: mismatched types: expected `core::ops::FnMut() -> core::result::Result<u32, std::io::IoError>`, found `closure[scratch.rs:14:9: 14:35]` (expected trait core::ops::FnMut, found closure)
scratch.rs:14         |&mut:| file.read_le_u32()
                      ^~~~~~~~~~~~~~~~~~~~~~~~~~

3 个答案:

答案 0 :(得分:4)

此处Shepmaster's answer没有Box

use std::io::{File,IoResult};
use std::iter::range_step;

fn main() {
    let path = Path::new("fid");
    let mut file = File::open(&path);
    let big = true;
    let mut fun_be;
    let mut fun_le;
    let mut fun: &mut FnMut() -> IoResult<u32> = if big {
        fun_be = |&mut:| file.read_be_u32();
        &mut fun_be as &mut FnMut() -> _
    } else {
        fun_le = |&mut:| file.read_le_u32();
        &mut fun_le as &mut FnMut() -> _
    };

    println!("{:?}", fun())
}

答案 1 :(得分:2)

在处理预先存在的功能时,实际上根本不需要关闭;你可以直接使用这些函数:

use std::io::{File,IoResult};
use std::iter::range_step;

fn main() {
    let path = Path::new("fid");
    let mut file = File::open(&path);
    let big = true;
    let fun: fn(_) -> _ = if big {
        Reader::read_be_u32
    } else {
        Reader::read_le_u32
    };

    println!("{:?}", fun(&mut file))
}

(唉: fn(_) -> _是必要的。我不确定它是否会在某些时候变得不必要。)

答案 2 :(得分:0)

以前,闭包会自动装箱,但现在我们已经取消装箱闭包。从效率的角度来看,这是一件好事!

但是,在您的情况下,您希望有一个实现特征的绑定,但我们不关心变量的实际类型。在这种情况下,特征是FnMut,具体类型是自动生成的类型,每个闭包都是唯一的。为此,我们需要一个特征对象(如&TraitBox<Trait>)。这是一个示例,我们重新打开未装箱的闭包,创建特征对象:

use std::io::{File,IoResult};
use std::iter::range_step;

fn main() {
    let path = Path::new("fid");
    let mut file = File::open(&path);
    let big = true;
    let mut fun: Box<FnMut() -> IoResult<u32>> = if big {
        Box::new(|&mut:| file.read_be_u32())
    } else {
        Box::new(|&mut:| file.read_le_u32())
    };

    println!("{:?}", fun())
}