memo.log

技術情報の雑なメモ

構造体が持っている配列の各要素の参照ベクターにして返す

以下のようにすることで、配列で持っている各要素の値を呼び出し側で変更できる

#[derive(Debug)]
struct Grid(
  [Cell; 3]
);

impl Grid {
  fn get_cells2(&mut self) -> Vec<&mut Cell>{
    return self.0.iter_mut().collect();
  }
}

#[derive(Debug)]
struct Cell(
  i32
);

fn main() {
  let mut grid = Grid([
    Cell(1),
    Cell(1),
    Cell(1)
  ]
  );

  println!("{:?}", grid); // 1
  let mut cells = grid.get_cells2();
  cells[0].0 = 100;
  println!("{:?}", grid); // 100
}

構造体の可変参照、不変参照

// 構造体
struct Test1{
  number1: i32,
  number2: i32
}

impl Test1 {
  // `&self` だと不変参照のため、代入しようとするとエラーになる
  //   cannot assign to `self.number1`, which is behind a `&` reference
  //   `self` is a `&` reference, so the data it refers to cannot be written
  //   fn test1(&self) {
  //     self.number1 = 100;
  //   }

  // 可変参照
  fn test2(&mut self) {
    self.number1 = 100;
  }
}

fn main() {
  let mut test1 = Test1 {
    number1: 1,
    number2: 2
  };

  println!("{:?}", test1.number1); // 1
  test1.test2();
  println!("{:?}", test1.number1); // 100
}

構造体のサンプルメモ

// 構造体
struct Test1{
  number1: i32,
  number2: i32
}

// タプル構造体
// フィールド名は無し
struct Test2(
  i32, i32
);

fn main() {
  let test1 = Test1 {
    number1: 1,
    number2: 2
  };
  // . でアクセス
  println!("{:?}", test1.number1); // 1

  let test2 = Test2(
    1, 2
  );
  // .0 とかでアクセス
  println!("{:?}", test2.0); //1
  println!("{:?}", test2.1); //2
}

所有権のメモ

  let d = String::from("d");
  let e = d;
  let f = d; // エラー。 変数 d は所有権を失っているため

  let g = &d; // 参照を渡すか、
  let h = d.clone(); // clone() する

  let arr = [String::from("a")];
  let ar = arr[0]; //配列のインデックスでデータを取る場合、ムーブ動作になるため、非Copy Trail のデータは取れないようになっているため、エラーになる

[Rust] 配列から直接非Copy Trait の要素の所有権の移動はできない =インデックスを用いて

以下の場合にエラーが出るのがよく分からなかった。 非CopyTrait のデータが配列の要素の場合に、インデックスを用いて参照できない。

  let arr = [String::from("a")];
  let ar = arr[0]; //  cannot move out of here
                   // move occurs because `arr[_]` has type `String`, which does not implement the `Copy` trait

公式ドキュメント等を読んでもよく分からなかったが、ChatGPT先生曰く以下のようだ。

配列から直接要素を「ムーブ」することが許されていない理由は、Rustの配列操作のセマンティクスと、所有権のルールに基づいています。Rustでは、配列から要素を取り出すとき、特に非Copyトレイトを持つ要素(例えばString型など)はデフォルトで参照として扱われます。Copyトレイトを持たない要素を配列からムーブしようとすると、元の配列がその要素への有効な参照を持っているため、所有権の問題が生じるためです。 具体的には、Rustの配列の要素アクセスは、要素への不変参照を返す操作として定義されており、これにより所有権が移動するような操作(ムーブ)はコンパイラによって阻止されます。この動作は、プログラムの安全性を保つために重要で、メモリ安全性の保障や、実行時エラーを防ぐために設計されています

具体的なオペレーションとしては以下のようにすればいいらしい。

要素を参照で取るか、

let ar = &arr[0];

明示的に Clone する。

let ar = arr[0].clone();

構造体を配列の要素にする場合は、 Clone と Copy Trait を実装すればよい。

  #[derive(Clone, Copy)]
  struct Cell {
    number: i32
  }

  let cells = [Cell{number: 0}];
  let j = cells[0];
}

[Rust]関数の戻り値とセミコロンについてのサンプルメモ

// 戻り値がない関数定義の場合、空のタプルと同じになる。
// つまり、以下の2つは同じ
fn test1a() {
}
fn test1b() -> () {
}

// 戻り値を指定させる方法は2つ
// 1. return キーワードとセミコロンをつけて返す
// 2. return キーワードを使わずセミコロンなしで返す
fn test2a() -> i32 {
  return 1;
}
fn test2b() -> i32 {
  1
}

// なので、例えば戻り値型を指定しない=空のタプルとするのに、
// 以下のようにセミコロンなしで返そうとするとコンパイルエラーになる
// fn test3() {
//  1 // mismatched types expected `()`, found integerrust/
// }

// 以下は () を返しているのでOK
fn test4() {
  ()
}

fn main() {
}

『パーフェクト Rust』の「7-1-4」が分かりやすい。