爲了嘗試重載調用語法,我引入了一個簡單的緩存,可以緩存昂貴的計算結果。我對使用一段語法有點困惑。我將在問題之前逐步介紹代碼。是否可以避免「FnOnce」的無意義定義?
緩存的目的是這樣使用:
fn fib(x: i32) -> i32 {
if x < 2 { x } else { fib(x-1) + fib(x-2) }
}
fn main() {
let mut cfib = Cache::new(fib);
// Loop that repeats computation and extracts it from the cache
// the second time.
for x in 1..200 {
let val = 5 * x % 40;
println!("fibc({}) = {}", val, cfib(val));
}
}
我們首先序言中啓用的功能尚未穩定:
#![feature(fn_traits, unboxed_closures)]
use std::collections::HashMap;
use std::hash::Hash;
我們介紹了緩存的結構與HashMap
和函數來計算新的值。
struct Cache<T, R> {
cache: HashMap<T, R>,
func: fn(T) -> R,
}
impl<T, R> Cache<T, R>
where T: Eq + Hash + Copy,
R: Copy
{
fn new(func: fn(T) -> R) -> Cache<T, R> {
Cache { cache: HashMap::new(), func: func }
}
fn compute(&mut self, x: T) -> R {
let func = self.func;
let do_insert = || (func)(x);
*self.cache.entry(x).or_insert_with(do_insert)
}
}
我創建FnMut
特徵的實現,因爲緩存需要是可變的。
impl<T, R> FnMut<(T,)> for Cache<T, R>
where T: Eq + Hash + Copy,
R: Copy
{
extern "rust-call" fn call_mut(&mut self, args: (T,))
-> Self::Output
{
let (arg,) = args;
self.compute(arg)
}
}
即使我找到的語法FnMut<(T,)>
很奇怪,這是好的,安全的,並傳達的意圖相當明顯。因爲我需要定義函數的返回類型,我還想寫開頭爲:
impl<T, R> FnMut<(T,), Output=R> for Cache<T, R>
where T: Eq + Hash + Copy,
R: Copy
{}
但失敗與錯誤:
error[E0229]: associated type bindings are not allowed here
--> src/main.rs:55:24
|
55 | impl<T, R> FnMut<(T,), Output=R> for Cache<T, R>
| ^^^^^^^^ associate type not allowed here
我不得不實施FnOnce
是這樣的:
impl<T, R> FnOnce<(T,)> for Cache<T,R>
where T: Eq + Hash + Copy,
R: Copy
{
type Output = R;
extern "rust-call" fn call_once(self, _arg: (T,))
-> Self::Output
{
unimplemented!()
}
}
這是自call_once
種毫無意義將永遠不會被調用,並從Associated Types看起來這應該是可能的。但是,它會因相關類型不允許的錯誤而失敗。
Rust Compiler Error Index提到語法Fn(T) -> R
並且還說Fn<(T,), Output=U>
應該可以工作,但即使我使用夜晚Rust編譯器,我也無法使其工作。
因爲希望在編譯時儘可能多地捕捉錯誤,所以最好避免在FnOnce
中創建「未實現」函數,因爲這會在運行時而不是編譯時失敗。
是否有可能僅實現FnMut
並以某種方式提供函數的返回類型?
看來工作。謝謝。 –
在這裏,「extern」是否需要「防鏽」? –
@MatthieuM。是的。該特徵定義了一個「extern」rust-call「函數,並且實現必須與特徵定義匹配。更廣泛地說,'rust-call'告訴編譯器'arg'實際上是函數的多個參數,並且執行轉換,以便每個元組值都是一個單獨的參數。據推測,傳遞給函數的單個大元組的行爲與硬件級別的許多單獨值不同。 – Shepmaster