簡體   English   中英

借用的向量引用的生命周期與它包含的借用指針之間的關系是什么?

[英]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]) -> &strfn test(xs: &[String]) -> &str

我有一種感覺,這個問題歸結為如何編譯器計算生命周期的(共同,反向, - )方差,或者更准確地說,它是如何在Rust 1.0之前為這種情況正確計算它的。 正確識別后,因為切片包含引用,所以引用必須比切片更長。 因此,可以安全地返回字符串切片,其壽命更短,匹配'r

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM