2016-12-01 68 views
0

我想要通过引用可以突变的特征中具有值。问题是,String值是非常大的,可能会被很多线程访问,所以我的解决方案看起来是这样的:将Arc <RwLock>转换为&mut

trait MyTrait { 
    fn name<'a>(&'a mut self) -> &'a mut String; 
} 

struct SimpleImpl { 
    name: String 
} 

impl MyTrait for SimpleImpl { 
    fn name<'a>(&'a mut self) -> &'a mut String { 
     &mut self.name 
    } 
} 

use std::sync::{Arc,RwLock}; 

struct ParallelImpl { 
    name: Arc<RwLock<String>> 
} 

impl MyTrait for ParallelImpl { 
    fn name<'a>(&'a mut self) -> &'a mut String { 
     self.name.get_mut().unwrap() 
    } 
} 

fn main() { 
    let mut a = SimpleImpl { name: String::from("simple") }; 
    let mut b = ParallelImpl { name: Arc::new(RwLock::new(String::from("parallel"))) }; 

    a.name().as_mut_str(); 
    b.name().as_mut_str(); 
} 

这种失败

main2.rs:23:9: 23:18 error: cannot borrow immutable borrowed content as mutable 
main2.rs:23   self.name.get_mut().unwrap() 

编译为什么我不能请致电get_mut()解开ArcRwLock

+0

这看起来像['owning_ref']的另一个工作(https://kimundi.github.io/owning-ref-rs/owning_ref/index.html)箱。它包含一个['RwLockWriteGuardRef'](https://kimundi.github.io/owning-ref-rs/owning_ref/type.RwLockWriteGuardRef.html)类型,它的行为非常像引用,但保留了警卫。 –

回答

5

请仔细看看RwLock的界面。

get_mut返回一个LockResult<&mut T>这是一个警戒对象。这个警卫的破坏会自动解锁。

为了让事情是安全的,您通过在保护调用unwrap()得到&mut T是从保护借贷,也就是unwrap()结果的寿命是由保护的限制(因为在警卫被破坏后,锁被解锁)。

在这里,您将创建临时保护,并立即把它扔了,所以参考的寿命不能超过该功能的...

Congratz生锈!在编译时阻止了另一个数据竞争:)

+0

所以我必须从'name()'返回'LockResult <&mut T>'? –

+0

@JohnMcCrae另一个将沿[这些行](http://stackoverflow.com/a/40853817/1600898)设计API。这将允许并行和非并行情况下的相同接口。 – user4815162342

+0

@JohnMcCrae:好吧,这有点复杂。直到Rust实现了对具有生命周期的关联类型进行参数化的能力,遗憾的是不可能返回从特征的不同实现中借用“Self”的不同类型...... –