我使用枚举来选择不同的功能签名。只要函数具有“正常”(大小)参数,例如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]); }
}
}
只要有一个切片作为参数,#[derive(Debug, Eq, PartialEq)]
就不再可能了。但在我的情况下,这不是问题。
我无法让FunctionSlice(fn(&[u8]) -> String),
工作。我必须使用具有静态生命周期的引用类型。否则#[derive(Copy, Clone)]
会失败。要初始化结构,我必须使用额外的静态。
我目前正在使用rust 1.10
答案 0 :(得分:3)
这与issue 28229有关:某些类型实现Copy
但不实现Clone
(即使Copy
是Clone
的子商标,所以这应该是不可能!)。这意味着您可以派生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
}
}
但这对于导出Debug
和PartialEq
没有帮助。只有将相应特征的实现添加到有问题的类型时,您才能够这样做。与此同时,您必须自己实施。 (Eq
如果提供PartialEq
,则可以派生{。{1}}。
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)
},
}
}
}