[英]Rust: How to specify lifetimes in closure arguments?
我正在編寫一個解析器生成器作為學習銹的項目,並且遇到了一些我無法使用生存期和結束時間解決的問題。 這是我的簡化情況(很抱歉,它是如此復雜,但是我需要在實際版本中使用自定義迭代器,這似乎對編譯器的行為有所影響):
游戲圍欄鏈接: http : //is.gd/rRm2aa
struct MyIter<'stat, T:Iterator<&'stat str>>{
source: T
}
impl<'stat, T:Iterator<&'stat str>> Iterator<&'stat str> for MyIter<'stat, T>{
fn next(&mut self) -> Option<&'stat str>{
self.source.next()
}
}
struct Scanner<'stat,T:Iterator<&'stat str>>{
input: T
}
impl<'main> Scanner<'main, MyIter<'main,::std::str::Graphemes<'main>>>{
fn scan_literal(&'main mut self) -> Option<String>{
let mut token = String::from_str("");
fn get_chunk<'scan_literal,'main>(result:&'scan_literal mut String,
input: &'main mut MyIter<'main,::std::str::Graphemes<'main>>)
-> Option<&'scan_literal mut String>{
Some(input.take_while(|&chr| chr != "\"")
.fold(result, |&mut acc, chr|{
acc.push_str(chr);
&mut acc
}))
}
get_chunk(&mut token,&mut self.input);
println!("token is {}", token);
Some(token)
}
}
fn main(){
let mut scanner = Scanner{input:MyIter{source:"\"foo\"".graphemes(true)}};
scanner.scan_literal();
}
我在這里知道兩個問題。 首先,我必須在get_chunk函數中隱藏主生命周期(我在impl
嘗試過使用它的主生命周期,但是編譯器抱怨'main
get_chunk
內部未定義get_chunk
)。 我認為它仍然可以工作,因為調用后get_chunk將匹配'main
從impl
與'main
從get_chunk
,但我不知道這是正確的。
第二個問題是,閉包內的&mut acc
的生存期必須為'scan_literal
,才能像我希望的那樣工作(在此示例中,直到第一個"
為止,一直累積字符)。我無法添加顯式生存期但是,對於&mut acc
,編譯器表示其生存期僅限於閉包本身,因此我無法返回引用以在fold的下一次迭代中使用。我已經獲得了以各種其他方式進行編譯和運行的函數,但我不明白這里是什么問題。
我的主要問題是:有沒有辦法明確指定閉包參數的生存期? 如果不是,是否有更好的方法使用fold來累積字符串而不進行多次復制?
首先,關於一生。 在其他函數內部定義的函數是靜態的,它們不以任何方式與其外部代碼連接。 因此,它們的壽命參數是完全獨立的。 您不希望將'main
用作get_chunk()
的生命周期參數,因為它會get_chunk()
外部的'main
生命周期,並且只會造成混亂。
接下來,關於閉包。 該表達式:
|&mut acc, chr| ...
很有可能不是您真正認為的那樣。 閉包/函數參數允許使用不可辯駁的模式,並且&
在模式中具有特殊含義。 即,它取消引用與之匹配的值,並將其標識符分配給該取消引用的值:
let x: int = 10i;
let p: &int = &x;
match p {
&y => println!("{}", y) // prints 10
}
你能想到的&
在一個圖案作為相反&
中的表達式:在表達它的意思是“需要參考”,在它的意思是“刪除引用”的圖案。
但是mut
不屬於&
在模式中; 它屬於標識符,表示具有該標識符的變量是可變的,即您不應寫
|&mut acc, chr| ...
但
|& mut acc, chr| ...
您可能對該RFC感興趣,而該RFC恰恰與此語言語法方面的問題有關。
看來您想做一件非常奇怪的事情,我不確定我了解您的去向。 您很可能混淆不同的字符串類型。 首先,您應該閱讀解釋所有權和借用以及何時使用它們的官方指南 (您可能還想閱讀未完成的所有權指南 ;它將很快進入主文檔樹),然后您應該閱讀字符串指南。 。
無論如何,您的問題可以通過更簡單,更通用的方式解決:
#[deriving(Clone)]
struct MyIter<'s, T: Iterator<&'s str>> {
source: T
}
impl<'s, T: Iterator<&'s str>> Iterator<&'s str> for MyIter<'s, T>{
fn next(&mut self) -> Option<&'s str>{ // '
self.source.next()
}
}
#[deriving(Clone)]
struct Scanner<'s, T: Iterator<&'s str>> {
input: T
}
impl<'m, T: Iterator<&'m str>> Scanner<'m, T> { // '
fn scan_literal(&mut self) -> Option<String>{
fn get_chunk<'a, T: Iterator<&'a str>>(input: T) -> Option<String> {
Some(
input.take_while(|&chr| chr != "\"")
.fold(String::new(), |mut acc, chr| {
acc.push_str(chr);
acc
})
)
}
let token = get_chunk(self.input.by_ref());
println!("token is {}", token);
token
}
}
fn main(){
let mut scanner = Scanner{
input: MyIter {
source: "\"foo\"".graphemes(true)
}
};
scanner.scan_literal();
}
您不需要將外部引用傳遞到閉包中。 您可以直接在fold()
操作中生成一個String
。 我還簡化了您的代碼,使其更加慣用。
請注意,現在impl
for Scanner
也可以與返回&str
任意迭代器一起使用。 這很可能是你想寫的不是這個專業Scanner
只與工作MyIter
與Graphemes
里面。 by_ref()
操作將I
為Iterator<T>
&mut I
轉換為J
,其中J
為Iterator<T>
。 即使您只有對原始迭代器的可變引用,它也允許迭代器的進一步鏈接。
順便說一下,您的代碼也不完整。 它只會返回Some("")
因為take_while()
會停在第一個引號上,並且不會進一步掃描。 您應該重寫它以考慮初始報價。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.