官术网_书友最值得收藏!

How to do it...

Understanding shared ownership only requires eight steps:

  1. In the fairly young ecosystem that is Rust, APIs and function signatures are not always the most efficient, especially when they require somewhat advanced knowledge of memory layout. So, consider a simple length function (add it to the mod tests scope): 
    /// 
/// A length function that takes ownership of the input
/// variable
///
fn length(s: String) -> usize {
s.len()
}

While unnecessary, the function requires that you pass your owned variable to the scope. 

  1. Luckily, the clone() function is ready for you if you still need ownership after the function call. This is similar to a loop, by the way, where ownership is moved in the first iteration, which means it is gone by the second iteration—leading to a compiler error. Let's add a simple test to illustrate these moves:
    #[test]
fn cloning() {
let s = "abcdef".to_owned();
assert_eq!(length(s), 6);
// s is now "gone", we can't use it anymore
// therefore we can't use it in a loop either!
// ... unless we clone s - at a cost! (see benchmark)
let s = "abcdef".to_owned();

for _ in 0..10 {
// clone is typically an expensive deep copy
assert_eq!(length(s.clone()), 6);
}
}
  1. This works, but creates a lot of clones of a string, only then to drop it shortly after. This leads to wasting resources and, with large enough strings, slows down the program. To establish a baseline, let's check this by adding a benchmark:

extern crate test;
use std::rc::Rc;
use test::{black_box, Bencher};

#[bench]
fn bench_string_clone(b: &mut Bencher) {
let s: String = (0..100_000).map(|_| 'a').collect();
b.iter(|| {
black_box(length(s.clone()));
});
}
  1. Some APIs require ownership of the input variables without a semantic meaning. For example, the length function from Step 1 pretends to require variable ownership, but unless mutability is also necessary, Rust's std::rc::Rc (short for Reference Counted) type is a great choice for avoiding heavyweight cloning or taking away ownership from the calling scope. Let's try it out by creating a better length function:

///
/// The same length function, taking ownership of a Rc
///
fn rc_length(s: Rc<String>) -> usize {
s.len() // calls to the wrapped object require no additions
}
  1. We can now continue to use the owned type after passing it into the function:
     #[test]
fn refcounting() {
let s = Rc::new("abcdef".to_owned());
// we can clone Rc (reference counters) with low cost
assert_eq!(rc_length(s.clone()), 6);

for _ in 0..10 {
// clone is typically an expensive deep copy
assert_eq!(rc_length(s.clone()), 6);
}
}
  1. After we have created a baseline benchmark, we certainly want to know how well the Rc version fares:
    #[bench]
fn bench_string_rc(b: &mut Bencher) {
let s: String = (0..100_000).map(|_| 'a').collect();
let rc_s = Rc::new(s);
b.iter(|| {
black_box(rc_length(rc_s.clone()));
});
}
  1. First, we should check whether the implementations are correct by running cargo test:
$ cargo test
Compiling sharing-ownership v0.1.0 (Rust-
Cookbook/Chapter02/sharing-ownership)
Finished dev [unoptimized + debuginfo] target(s) in 0.81s
Running target/debug/deps/sharing_ownership-f029377019c63d62

running 4 tests
test tests::cloning ... ok
test tests::refcounting ... ok
test tests::bench_string_rc ... ok
test tests::bench_string_clone ... ok

test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

Doc-tests sharing-ownership

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
  1. Now, we can check which variation is faster, and what the differences are:
$ cargo bench
Compiling sharing-ownership v0.1.0 (Rust-
Cookbook/Chapter02/sharing-ownership)
Finished release [optimized] target(s) in 0.54s
Running target/release/deps/sharing_ownership-68bc8eb23caa9948

running 4 tests
test tests::cloning ... ignored
test tests::refcounting ... ignored
test tests::bench_string_clone ... bench: 2,703 ns/iter (+/- 289)
test tests::bench_string_rc ... bench: 1 ns/iter (+/- 0)

test result: ok. 0 passed; 0 failed; 2 ignored; 2 measured; 0 filtered out

After we have explored shared ownership with Rc, let's go behind the scenes to understand them better.

主站蜘蛛池模板: 宜城市| 横峰县| 双城市| 手游| 兴文县| 同心县| 会昌县| 延安市| 通城县| 元朗区| 新营市| 万载县| 英德市| 齐齐哈尔市| 石泉县| 旬邑县| 营口市| 肥东县| 富裕县| 睢宁县| 光泽县| 涡阳县| 大新县| 抚松县| 沐川县| 宜都市| 新疆| 沙雅县| 冀州市| 金坛市| 高要市| 昌图县| 云和县| 平定县| 荆门市| 洪雅县| 宁都县| 都兰县| 香河县| 梨树县| 石狮市|