5

编者注:此代码示例来自 Rust 1.0 之前的版本,在语法上不是有效的 Rust 1.0 代码。此代码的更新版本会产生不同的错误,但答案仍然包含有价值的信息。

我在 Rust 0.6 中尝试了这段代码:

fn test<'r>(xs: &'r [&str]) -> &'r str {
    return xs[0];
}

我认为这种类型签名的意思是:“test 需要一个借用的指针,其生命周期为 'r,指向一个借用的指向字符串的指针向量,并返回一个借用的指向字符串的指针,也具有生命周期 '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]

计划是:创建一个包含所有借用指针的扩展列表,使用它,然后释放扩展列表,然后释放拥有指针的原始列表,包括包含的字符串。

4

4 回答 4

5

具有拥有/唯一字符串的第二个版本test确实可以工作,只是必须帮助编译器将 转换~str为 a &'r str

fn test<'r>(xs: &'r [~str]) -> &'r str {
    let tmp: &'r str = xs[0];
    tmp
}

这样做的原因是xs向量拥有~str它所包含的 s ,因此编译器知道它们的生命周期至少是向量的生命周期(因为它在存在这样的借用时也要小心可变性,所以字符串永远不会从向量中删除)。唯一的问题是说服编译器强制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不可行,这可能是一个错误(我现在正在调查它,我打开了#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"]
于 2013-05-21T08:01:02.037 回答
3

我认为你的意思是:

fn test<'r>(xs: &[&'r str]) ->  &'r str {
        return xs[0];
}

也就是说,您获取一个借用的数组指针,其中包含指向具有生命周期 r 的字符串的借用指针,并返回这些指针之一,相同的生命周期。向量本身的生命周期无关紧要。

这就是您的第二个示例不起作用的原因,因为您正在返回一个未在函数输入中借用的借用指针:数组是借用的,其内容不是。

于 2013-05-20T10:17:57.127 回答
0

我认为这就是你的意思:

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));
}

特别是对于字符串,它可能不太好(因为字符串总是通过引用),但是对于值向量 - 它工作得很好。

于 2013-05-20T10:33:01.337 回答
0

从 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)有任何明确的生命周期

我有一种感觉,这个问题归结为编译器如何计算生命周期的(co-,contra-,in-)方差,或者更准确地说,它是如何在 Rust 1.0 之前没有正确计算这种情况的。正如您正确识别的那样,因为切片包含引用,所以引用必须比切片更有效。因此,返回匹配生命周期较短的字符串切片是安全的'r

于 2017-08-12T14:28:15.993 回答