2016-08-01 1 views
1

Я использую перечисление для выбора между различными сигнатурами функций. Пока функция имеет «нормальные» (размерные) параметры, такие как u8, это отлично работает. Но как только я использую функцию с параметром slice в качестве параметра, я получаю ошибки компилятора. Я нашел обходное решение, но я не уверен, что это единственный способ решить эту проблему. И я не понимаю, почему. Предполагая, что функция хранится как указатель, как параметры изменяются, что возможно?Используйте перечисление с функцией, которая имеет параметр среза

#[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 (даже если Copy является subtrait из 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 предусмотрено.)

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