如何为泛型使用括号?
How to use parentheses for generics?
我收到编译错误:
尖括号符号在与 Fn
系列特性一起使用时不稳定,请使用括号 [E0215]
这是什么意思?我如何"use parentheses"?
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;
}
你的代码有几个问题。
首先,你不能在稳定的 Rust 中直接使用 Fn*
traits。这包括 1) 使用尖括号表示法,以及 2) 实现这些特征。不过,在不稳定的 Rust 中,可以为这两个东西启用功能标志。
其次,如果你确实使用尖括号作为闭包特征,你必须使用元组作为参数,即使只有一个参数:
FnOnce<(A,)>
第三,错误信息是你应该写FnOnce(T, U) -> V
而不是FnOnce<(T, U), Output=V>
。这就是 "using parentheses" 消息下的含义。我同意此消息在这里具有误导性,因为由于关联类型,您无法像这样编写 Fn
。我想关于实现 Fn
类型的错误应该优先于这个错误。
第四,当你使用 &'a MemoedFun<A, R>
时,你将无法做你想做的事情(由哈希映射支持的记忆函数),因为你需要一个可变指针来更新映射。您需要为 &'a mut MemoedFun<A, R>
:
实施 FnOnce
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)
}
}
}
最后,为使用此记忆器而必须编写的结果代码并不漂亮。由于某些原因,您不能在 "function" 上使用函数语法,因此您需要直接使用 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*
traits手动实现不稳定是有原因的
我收到编译错误:
尖括号符号在与 Fn
系列特性一起使用时不稳定,请使用括号 [E0215]
这是什么意思?我如何"use parentheses"?
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;
}
你的代码有几个问题。
首先,你不能在稳定的 Rust 中直接使用 Fn*
traits。这包括 1) 使用尖括号表示法,以及 2) 实现这些特征。不过,在不稳定的 Rust 中,可以为这两个东西启用功能标志。
其次,如果你确实使用尖括号作为闭包特征,你必须使用元组作为参数,即使只有一个参数:
FnOnce<(A,)>
第三,错误信息是你应该写FnOnce(T, U) -> V
而不是FnOnce<(T, U), Output=V>
。这就是 "using parentheses" 消息下的含义。我同意此消息在这里具有误导性,因为由于关联类型,您无法像这样编写 Fn
。我想关于实现 Fn
类型的错误应该优先于这个错误。
第四,当你使用 &'a MemoedFun<A, R>
时,你将无法做你想做的事情(由哈希映射支持的记忆函数),因为你需要一个可变指针来更新映射。您需要为 &'a mut MemoedFun<A, R>
:
FnOnce
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)
}
}
}
最后,为使用此记忆器而必须编写的结果代码并不漂亮。由于某些原因,您不能在 "function" 上使用函数语法,因此您需要直接使用 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*
traits手动实现不稳定是有原因的