2015-07-11 3 views
6

Я получаю ошибку компиляции:Как использовать круглые скобки для дженериков?

угла скобка обозначения не является стабильным при использовании с Fn семейства признаков, используйте круглые скобки [E0215]

Что это значит? Как использовать круглые скобки?

use std::hash::Hash; 
use std::collections::HashMap; 

struct MemoedFun<A, R> { 
    fun: fn(&A) -> R, 
    map: HashMap<A, R>, 
} 

fn memoize<A: Eq + Hash, R>(fun: fn(&A) -> R) -> MemoedFun<A, R> { 
    MemoedFun { 
     fun: fun, 
     map: HashMap::new(), 
    } 
} 

impl<'a, A, R> FnOnce<A> for &'a MemoedFun<A, R> { 
    type Output=&'a R; 
} 

ответ

8

С кодом возникает несколько проблем.

Прежде всего, вы не можете использовать Fn* черты непосредственно в стабильной ржавчине. Это включает в себя 1) использование нотации с угловыми скобками и 2) реализацию этих признаков. Однако можно включить флаг функции для обеих этих вещей в нестабильном Rust.

Во-вторых, если вы используете угловые скобки для закрытия признаков, вы должны использовать кортежи аргументы, даже если есть только один аргумент:

FnOnce<(A,)> 

В-третьих, сообщение об ошибке, что вместо FnOnce<(T, U), Output=V> вас следует написать FnOnce(T, U) -> V. Это то, что подразумевается под сообщением «Использование круглых скобок». Я согласен с тем, что это сообщение вводит в заблуждение, потому что вы не можете реализовать Fn, когда оно написано так из-за связанных типов. Я предполагаю, что ошибка в реализации типов Fn должна иметь приоритет над этой ошибкой.

В-четвертых, вы не сможете делать то, что хотите (функция memoizing, поддерживаемая картой хэша), когда вы используете &'a MemoedFun<A, R>, потому что вам нужен изменяемый указатель для обновления карты. Вы должны реализовать FnOnce для &'a mut MemoedFun<A, R>:

impl<'a, A: Eq + Hash, R> FnOnce<(A,)> for &'a mut MemoedFun<A, R> { 
    type Output = &'a R; 

    extern "rust-call" fn call_once(self, (arg,): (A,)) -> &'a R { 
     if self.map.contains_key(&arg) { 
      &self.map[&arg] 
     } else { 
      let r = (self.fun)(&arg); 
      self.map.entry(arg).or_insert(r) 
     } 
    } 
} 

И, наконец, полученный код придется написать, чтобы использовать этот memoizer не очень. Вы не можете использовать синтаксис функции на вашей «функции» по какой-то причине, так что вам нужно будет использовать call_once() непосредственно:

fn computer(x: &i32) -> i32 { 
    println!("Computing for {}", x); 
    -*x 
} 

let mut f = memoize(computer); 

println!("f(10): {}", (&mut f).call_once((10,))); 
println!("f(10): {}", (&mut f).call_once((10,))); 
println!("f(42): {}", (&mut f).call_once((42,))); 

(попробуйте это here)

Существует причина, почему Fn* качество ручной реализации не стабилизирован, в конце концов.

+0

Есть ли ржавая ошибка для этого вводящего в заблуждение сообщение об ошибке? Я не мог найти ничего по наивному поиску, – llogiq

+0

Я тоже его не нашел, поэтому я думаю, что имеет смысл его создать. –

+0

Что означает FnOnce (T, U) -> V? Я не могу найти описание этого синтаксиса. Выводится ли специальное ключевое слово? – dspyz