2016-08-01 38 views
1

我使用枚舉在不同的函數簽名之間進行選擇。只要該函數具有「正常」(大小)的參數,如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)]會失敗。要初始化結構,我必須使用一個額外的靜態。

我目前使用的防鏽1.10

回答

3

這與issue 28229:某些類型的實現Copy但不Clone(即使CopyClone一個subtrait,所以這應該是不可能的!)。這意味着你可以派生Copy但你不能派生Clone。可以通過複製self手動執行Clone來解決此問題。

#[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得出。)

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) 
      }, 
     } 
    } 
} 
+0

我加入PartialEq'和'Debug'的'的實現,因爲我確實需要他們現在。 (爲我的單位測試)。你的回答也幫助我解決了這個問題! – wimh