Как использовать скобки для дженериков?

Я получаю ошибку при компиляции:

обозначение углового кронштейна не стабильно при использовании с 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;
}

1 ответов


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

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

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

FnOnce<(A,)>

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

в-четвертых, вы не сможете делать то, что хотите (функция запоминания поддерживается хэш-картой) при использовании &'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,)));

(попробуй здесь)

есть причина, почему Fn* черты характера в конце концов, ручное внедрение не стабилизировалось.