スポンサーリンク

RustのsharedポインタRcを使ってみる

Rustでは、変数に対する=式で変数の所有権が移動してしまう。従って、安易に=代入するとmoveが発生してしまいコンパイルできなくなる。

#[derive(Debug)]
struct Color{
  r:f32,
  g:f32,
  b:f32
}

impl Color{
  fn new(R:f32,G:f32,B:f32)->Color{
    return Color{r:R,g:G,b:B};
  }
}


fn main() {

  let color = Color::new(0.5,0.2,0.0);

  let ref1 = color;
  let ref2 = color; // ref1にcolorが入っているのでcolorは空。

  println!("{:?}",color);

}

これを避けるには参照(&T)を使うか、Rcという参照カウンタを持つスマートポインタを使う。C++でいうところのshared_ptr。

ここで重要な違いだが、

・Rc ... それぞれが所有権を持つ。すべてのRcが破棄された時が変数(の値)の寿命

・&T ... 参照は所有権を持たないので、有効範囲が参照元の変数の寿命に依存する。

Rc::new()でポインタを作成し、clone()で参照を複製する。

use std::rc::Rc;

#[derive(Debug)]
struct AB{
  a:i32,
  b:i32,
}
//////////////////////////////////////////////////
fn main( ){

  let ref3;

  {
    // Sharedポインタ作成
    let myref=Rc::new(AB{a:5,b:10});
    {

      // ポインタを複製。値の複製ではない
      let ab=myref.clone();

      println!("{:?}",ab);

      // 参照カウント
      println!("Reference Count ab: {}",Rc::strong_count(&ab));

    }

    // ref3は所有権を持つので、
    // myrefのスコープが切れても値は破棄されない
    ref3 = myref.clone();
  }
  println!("Reference Count ref3: {}",Rc::strong_count(&ref3));

  // myrefは無効
  // ref3 は有効
  let k = ref3.a;

  println!("{}",k);

}

nullptr

Rustにはnullptrがない。Rcが無効であることを表現できないので、Optionと組み合わせる。

Optionは値があればSomeの中に入っている。値がなければNoneを持つ。

use std::{rc::Rc};

#[derive(Debug)]
struct Color{
  r:f32,
  g:f32,
  b:f32
}

impl Color{
  fn new(R:f32,G:f32,B:f32)->Color{
    return Color{r:R,g:G,b:B};
  }
}


//////////////////////////////////////////////////
fn main( ){

  let my_color = Color::new(0.5, 0.4, 0.3);

  // nullptrができないのでOptionと組み合わせる
  let mut data: Option<Rc<Color>> = None;

  // Optionなので、Option::Someに値を入れる
  data = Some(Rc::new(my_color));

  if let Some(color) = data{// dataが有効ならcolorを定義して代入
    println!("{:?}",color);
  }
  else{
    println!("nullptr");
  }

}

管理の移管

Rc::newにメモリ管理を移管するのは簡単だが、その逆はできないらしい。即ち、一度Rcで管理すると決めたら、もう自分で管理できなくなる。

use std::rc::Rc;

#[derive(Debug)]
struct AB{
  a:i32,
  b:i32,
}
//////////////////////////////////////////////////
fn main( ){

  let ab = AB{a:5,b:10};
  
  let myref=Rc::new(ab);// abからmyrefにmoveするので、以後 ab は使えない

  println!("{:?}",myref);// ここで ab を使おうとするとビルドエラー 


}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: