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

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.

主站蜘蛛池模板: 波密县| 寻乌县| 连山| 延川县| 通江县| 仁寿县| 凌海市| 阳原县| 临安市| 昆山市| 威宁| 乌拉特后旗| 信丰县| 米易县| 高邮市| 亳州市| 原阳县| 瑞金市| 大邑县| 溆浦县| 石泉县| 兴海县| 辽阳县| 许昌县| 安图县| 康定县| 登封市| 文昌市| 田阳县| 泊头市| 永善县| 南城县| 奉节县| 汉阴县| 遵义市| 革吉县| 盐津县| 安龙县| 云龙县| 昌黎县| 故城县|