[英]Casting a borrowed reference with a lifetime to a raw pointer in Rust
[英]What is the relationship between the lifetime of a borrowed reference to a vector and the borrowed pointers it contains?
編者注:此代碼示例來自1.0之前的Rust版本,並且在語法上不是有效的Rust 1.0代碼。 此代碼的更新版本會產生不同的錯誤,但答案仍包含有價值的信息。
我在Rust 0.6中嘗試了這段代碼:
fn test<'r>(xs: &'r [&str]) -> &'r str {
return xs[0];
}
我認為這種類型的簽名意味着:“測試將帶有生命周期'的借用指針帶到一個借用指向字符串的指針的向量,並將一個借用的指針返回給一個字符串,也帶有生命周期'r。但編譯器說:
refs.rs:2:8: 2:12 error: mismatched types: expected `&'r str` but found `&str` (lifetime mismatch)
refs.rs:2 return xs[0];
^~~~
refs.rs:1:39: 3:1 note: the lifetime &'r as defined on the block at 1:39...
refs.rs:1 fn test<'r>(xs: &'r [&str]) -> &'r str {
refs.rs:2 return xs[0];
refs.rs:3 }
refs.rs:1:39: 3:1 note: ...does not necessarily outlive the anonymous lifetime #1 defined on the block at 1:39
refs.rs:1 fn test<'r>(xs: &'r [&str]) -> &'r str {
refs.rs:2 return xs[0];
refs.rs:3 }
error: aborting due to previous error
這似乎意味着向量中的指針可能不會像(只讀)向量本身一樣長。 這可能嗎?
我需要做一些額外的注釋來告訴編譯器這沒關系嗎?
同樣,擁有指針的向量怎么樣? 例如
fn test<'r>(xs: &'r [~str]) -> &'r str {
return xs[0];
}
同樣,我希望能夠借用指向向量元素的指針,至少只要我借用了整個列表。
對於上下文,我最初的問題是嘗試使用自有指針列表擴展借用點列表:
fn extend<'r>(xs: ~[&'r str], ys: &'r [~str]) -> ~[&'r str]
計划是:創建一個帶有所有借用指針的exended列表,使用它,然后釋放擴展列表,然后釋放擁有指針的原始列表,包括包含的字符串。
第二個版本的test
,擁有/唯一字符串確實有效,只需要協助編譯器將~str
轉換為&'r str
:
fn test<'r>(xs: &'r [~str]) -> &'r str {
let tmp: &'r str = xs[0];
tmp
}
這個工作的原因是xs
vector擁有它包含的~str
,因此編譯器知道它們的生命周期至少是向量的生命周期(因為它在存在這樣的借位時也要小心可變性,所以字符串永遠不能從矢量中刪除)。 唯一的問題是說服編譯器將xs[0]
強制轉換為切片,這最容易通過臨時執行。
extend
可能看起來像:
fn extend<'r>(xs: ~[&'r str], ys: &'r [~str]) -> ~[&'r str] {
let mut xs = xs;
for vec::each(ys) |s| {
let tmp: &'r str = *s;
xs.push(tmp)
}
xs
}
似乎vec::each(ys)
有效,但是ys.each
沒有,這可能是一個bug( 我正在調查它現在我打開#6655 )。
如果要在原位修改向量,通常的方法是將可變引用傳遞給向量,即
fn extend<'r>(xs: &mut ~[&'r str], ys: &'r [~str]) {
for vec::each(ys) |s| {
let tmp: &'r str = *s;
xs.push(tmp)
}
}
這被稱為像extend(&mut vec, additions)
。
為了顯示:
rusti> let a = &[~"a", ~"b", ~"c"];
()
rusti> test(a)
"a"
rusti> extend(~["1", "2", "3"], a)
~["1", "2", "3", "a", "b", "c"]
我想你的意思是:
fn test<'r>(xs: &[&'r str]) -> &'r str {
return xs[0];
}
也就是說,你將一個借來的數組指針包含帶有生命周期r的字符串的借用指針,並返回其中一個指針,相同的生命周期。 載體本身的壽命是無關緊要的。
這就是你的第二個例子不起作用的原因,因為你正在返回一個借用的指針,這個指針沒有借用在函數的輸入中:數組是借用的,它的內容不是。
我認為這就是你的意思:
fn get1<'r, T>(xs: &'r [T]) -> &'r T {
return &xs[0];
}
fn main() {
let a = ~[1, 2, 3];
let b = [1, 2, 3];
let c = @[1, 2, 3];
let ax = get1(a);
let bx = get1(b);
let cx = get1(c);
println(fmt!("%d %d %d", *ax, *bx, *cx));
}
特別是對於字符串,它可能不太好(因為字符串總是按引用),但是使用值向量 - 它可以正常工作。
從Rust 1.19.0開始(可能從Rust 1.0開始), 原始代碼按預期工作 :
fn test<'r>(xs: &'r [&str]) -> &'r str {
xs[0]
}
fn main() {}
更新語法后 , 擁有的字符串版本也可以使用 :
fn test<'r>(xs: &'r [String]) -> &'r str {
&xs[0]
}
fn main() {}
更好的是,終身推理意味着你不需要在函數上有任何明確的生命周期( fn test(xs: &[&str]) -> &str
, fn test(xs: &[String]) -> &str
)
我有一種感覺,這個問題歸結為如何編譯器計算生命周期的(共同,反向, - )方差,或者更准確地說,它是如何在Rust 1.0之前為這種情況正確計算它的。 正確識別后,因為切片包含引用,所以引用必須比切片更長。 因此,可以安全地返回字符串切片,其壽命更短,匹配'r
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.