我會將答案分爲兩部分,第一部分是關於如何修正返回類型而不考慮借用檢查器,第二部分是爲什麼即使您修復返回類型也不起作用。
§1。
每封都有一個唯一的,匿名類型,所以c
不能是任何類型的F
主叫提供的。這意味着這條線將永遠不會編譯:
let c: F = |row: &Row| { ... } // no, wrong, always.
相反,類型應該從dump
功能,即像被傳播出去:
// ↓ no generics
pub fn dump(&self) -> MappedRows<「type of that c」> {
..
}
穩定的鏽不提供一種方式來命名類型。但是,我們可以在夜間做這樣的「IMPL特質」的功能:
#![feature(conservative_impl_trait)]
// ↓~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pub fn dump(&self) -> MappedRows<impl FnMut(&Row) -> DateTime<UTC>> {
..
}
// note: wrong, see §2.
的impl F
這裏指的是,「我們要返回MappedRows<T>
類型,其中T: F
,但我們不打算指定到底是什麼T
;來電者應該準備好將F
作爲T
的候選人來對待「。
由於您的封閉不會捕獲任何變量,事實上您可以將c
轉換爲函數。我們可以命名一個函數指針類型,而不需要「impl Trait」。
// ↓~~~~~~~~~~~~~~~~~~~~~~~~
pub fn dump(&self) -> MappedRows<fn(&Row) -> DateTime<UTC>> {
let mut stmt = self.conn.prepare("SELECT created_at FROM work ORDER BY created_at ASC").unwrap();
fn c(row: &Row) -> DateTime<UTC> {
row.get(0)
}
stmt.query_map(&[], c as fn(&Row) -> DateTime<UTC>).unwrap()
}
// note: wrong, see §2.
無論如何,如果我們確實使用了「IMPL特質」,因爲MappedRows
作爲一個Iterator,它是比較合適的,只是這麼說:
#![feature(conservative_impl_trait)]
pub fn dump<'c>(&'c self) -> impl Iterator<Item = Result<DateTime<UTC>>> + 'c {
..
}
// note: wrong, see §2.
(不'c
界限,編譯器將抱怨E0564,看起來終身elision不能與impl Trait一起使用)
如果你被Stable Rust卡住了,你不能使用「impl Trait」功能。你可以換性狀對象在一個盒子裏,在堆分配和動態調度的代價:
pub fn dump(&self) -> Box<Iterator<Item = Result<DateTime<UTC>>>> {
...
Box::new(stmt.query_map(&[], c).unwrap())
}
// note: wrong, see §2.
§2。
上述修補程序的工作原理,如果你想,比如說,只需return an independent closure or iterator。但如果您返回rusqlite::MappedRows
,則不起作用。編譯器不會允許上述工作由於一生問題:
error: `stmt` does not live long enough
--> 1.rs:23:9
|
23 | stmt.query_map(&[], c).unwrap()
| ^^^^ does not live long enough
24 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the body at 15:80...
--> 1.rs:15:81
|
15 | pub fn dump(conn: &Connection) -> MappedRows<impl FnMut(&Row) -> DateTime<UTC>> {
| ^
這是正確的。 MappedRows<F>
實際上是MappedRows<'stmt, F>
,只有當原始SQLite語句對象(具有'stmt
生存期)超過它時,此類型纔有效 - 因此,編譯器會在返回函數時抱怨stmt
已死亡。
確實,如果在迭代這些行之前語句被刪除,我們將得到垃圾結果。壞!
我們需要做的是確保在刪除語句之前讀取所有行。
你可以收集行到一個載體,由此從語句解離的結果,在存儲的一切在內存中的成本:
// ↓~~~~~~~~~~~~~~~~~~~~~~~~~
pub fn dump(&self) -> Vec<Result<DateTime<UTC>>> {
..
let it = stmt.query_map(&[], c).unwrap();
it.collect()
}
或反轉的控制,讓dump
接受功能,dump
同時保持stmt
活着,是使調用語法怪異的成本將撥打:
// ↓~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pub fn dump<F>(&self, mut f: F) where F: FnMut(Result<DateTime<UTC>>) {
...
for res in stmt.query_map(&[], c).unwrap() {
f(res);
}
}
x.dump(|res| println!("{:?}", res));
或分割dump
成兩個功能,並且讓呼叫者守聲明還活着,在中間構建暴露給用戶的成本:
#![feature(conservative_impl_trait)]
pub fn create_dump_statement(&self) -> Statement {
self.conn.prepare("SELECT '2017-03-01 12:34:56'").unwrap()
}
pub fn dump<'s>(&self, stmt: &'s mut Statement) -> impl Iterator<Item = Result<DateTime<UTC>>> + 's {
stmt.query_map(&[], |row| row.get(0)).unwrap()
}
...
let mut stmt = x.create_dump_statement();
for res in x.dump(&mut stmt) {
println!("{:?}", res);
}
非常感謝您的詳細解答。 – simao