使用带有切片参数的函数的枚举

时间:2016-08-01 00:34:12

标签: rust

我使用枚举来选择不同的功能签名。只要函数具有“正常”(大小)参数,例如u8,这就可以正常工作。但是一旦我使用带有切片的函数作为参数,我就会遇到编译器错误。我找到了一个解决方法,但我不确定这是否是解决这个问题的唯一方法。我不明白为什么。假设函数存储为指针,参数如何改变可能的?

#[derive(Copy, Clone/*, Debug, Eq, PartialEq*/)]
pub enum Function {
    FunctionVal(fn(u8) -> String),
    //FunctionSlice(fn(&[u8]) -> String), // E0277
    FunctionSlice(&'static fn(&[u8]) -> String), // workaround
}

#[derive(Copy, Clone/*, Debug, Eq, PartialEq*/)]
pub struct FunctionStruct {
    pub func: Function,
}

pub static FUNC1: FunctionStruct = FunctionStruct {
    func: Function::FunctionVal(convert_u8_to_string),
};

static F2:fn(&[u8]) -> String = convert_u8slice_to_string;
pub static FUNC2: FunctionStruct = FunctionStruct {
    func: Function::FunctionSlice(&F2), // to avoid E0308
};

fn convert_u8_to_string(_:u8) -> String { String::from("") }
fn convert_u8slice_to_string(_:&[u8]) -> String { String::from("") }

fn main() {
    let f = FUNC1;

    match f.func {
        Function::FunctionVal(f) => { f(0); }
        Function::FunctionSlice(f) => { f(&[0u8]); }
    }
}

(Rust Playground)

只要有一个切片作为参数,#[derive(Debug, Eq, PartialEq)]就不再可能了。但在我的情况下,这不是问题。

我无法让FunctionSlice(fn(&[u8]) -> String),工作。我必须使用具有静态生命周期的引用类型。否则#[derive(Copy, Clone)]会失败。要初始化结构,我必须使用额外的静态。

我目前正在使用rust 1.10

1 个答案:

答案 0 :(得分:3)

这与issue 28229有关:某些类型实现Copy但不实现Clone(即使CopyClone的子商标,所以这应该是不可能!)。这意味着您可以派生Copy,但无法派生Clone。通过复制Clone手动实施self,可以解决此问题。

#[derive(Copy)]
pub enum Function {
    FunctionVal(fn(u8) -> String),
    FunctionSlice(fn(&[u8]) -> String),
}

impl Clone for Function {
    fn clone(&self) -> Self {
        *self
    }
}

但这对于导出DebugPartialEq没有帮助。只有将相应特征的实现添加到有问题的类型时,您才能够这样做。与此同时,您必须自己实施。 (Eq如果提供PartialEq,则可以派生{。{1}}。

For example

impl PartialEq for Function {
    fn eq(&self, other: &Function) -> bool {
        match (self, other) {
            (&Function::FunctionVal(a), &Function::FunctionVal(b)) => a == b,
            (&Function::FunctionSlice(a), &Function::FunctionSlice(b)) => a as usize == b as usize,
            _ => false,
        }
    }
}

impl fmt::Debug for Function {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Function::FunctionVal(ref p) => {
                try!(f.write_str("FunctionVal:"));
                fmt::Pointer::fmt(p, f)
            },
            &Function::FunctionSlice(ref p) => {
                try!(f.write_str("FunctionSlice:"));
                fmt::Pointer::fmt(&(*p as *const ()), f)
            },
        }
    }
}