首页 文章

尝试使用std :: util :: replace时的借用问题

提问于
浏览
4
use std::util::replace;

假设我们有这些结构:

struct Foo {
    a: ~[Baz],
}

struct Bar {
    a: ~[Quux],
}

struct Baz {
    x: bool
}

struct Quux {
    x: bool,
    y: Bar,
}

以下工作正常:

let mut foo = Foo{a: ~[Baz {x: true},
                           Baz {x: false}]};

    println!("{}, {}", foo.a[0].x, foo.a[1].x); // true false
    replace(&mut foo.a[0], foo.a[1]);
    println!("{}, {}", foo.a[0].x, foo.a[1].x); // false false

但是,这不起作用:

let mut bar = Bar{a: ~[Quux {x: true, y: Bar {a: ~[]} },
                           Quux {x: false, y: Bar {a: ~[]} }]
    };

    println!("{}, {}", bar.a[0].x, bar.a[1].x); // true false

    replace(&mut bar.a[0], bar.a[1]);
}

编译器给出的错误是:

foobar_borrow2.rs:35:28: 35:36 error: cannot move out of `(*bar.a)[]` because it is borrowed
foobar_borrow2.rs:35     replace(&mut bar.a[0], bar.a[1]);
                                                ^~~~~~~~
foobar_borrow2.rs:35:13: 35:26 note: borrow of `(*bar.a)[]` occurs here
foobar_borrow2.rs:35     replace(&mut bar.a[0], bar.a[1]);
                                 ^~~~~~~~~~~~~

我不明白这意味着什么 . 这似乎与之前的案例类似,但是有效 . 为什么将 Bar 字段添加到 Quux 导致它失败?

2 回答

  • 2

    我想我现在明白了,但首先我认为's worthwhile to simplify. Let'将_1275350改为:

    struct Quux {
            x: ~bool,
    }
    

    这会导致相同的错误 . 回想一下 Foo.aBaz 的唯一向量 . Baz 具有复制语义,因为它是一个结构,其字段都具有复制语义(即单个 int 字段) . 因此,将 foo.a[1] 传递给 replace 的第二个参数会导致其值被复制 .

    另一方面, Bar.aQuux 的唯一向量 . Quux 具有移动语义,因为它的唯一字段是指向布尔值的拥有指针 . 因此,当我们将 bar.a[1] 传递给 replace 时,它会尝试将向量 bar.a 的所有权移至 replace . 但我们不能这样做,因为(显然?)在 replace 的第一个参数中采用 bar.a[0] 的可变借用导致整个向量已被借用 .

    在这个简单的例子中我们可以看到关于向量的最后一个事实

    let mut x = ~[1, 5, 9];
    let y = &mut x[0];
    let z = &x[1]; //error: cannot borrow (*x)[] as immutable because it is already borrowed as mutable
    

    在我的原始示例中, Quux 具有移动语义,因为它具有 Bar 字段,并且 Bar 具有移动语义,因为它具有向量作为其字段之一 . 所以相同的原则在起作用 .

  • 0

    这里替换函数获取借用 bar 的所有权,当编译器到达第一次使用bar时,这是 bar.a[0]

    replace(&mut bar.a[0], bar.a[1]);

    在此之后,在函数完成之前,编译器会阻止进一步使用 bar . 不幸的是,这会阻止函数的第二个参数被接受,因为它是在此刻采取的 .

    另一种方法是将 bar.a[1] 的内容复制到一个新变量中,并将此新变量作为第二个参数发送到 replace()

    let a1 = bar.a[1].clone();
    replace(&mut bar.a[0], a1);
    

    这会将bar.a [1]中的值复制到新变量中 .

    这将需要bar及其内容来实现特征 std::clone::Clone . 对于此示例,将 #[deriving(Clone] 添加到Bar和Quuz将起作用 .

    #[deriving(Clone)]
    struct Quux {
        x: bool,
        y: Bar,
    }  
    
    #[deriving(Clone)]
    struct Bar {
        a: ~[Quux],
    }
    

相关问题