🦀

100日後にRustをちょっと知ってる人になる: [Day 82]書籍: Rust プログラミング完全ガイド その6

2022/12/09に公開

Day 82 のテーマ

Day 81 までに Rust の書籍の Rustプログラミング完全ガイド の 1 章から 11 章までを読み終わりました。

今週中にこの書籍を読み終えるためには少しペースを上げねばと思う今日この頃。さて、今日はどこまで読み進められるでしょうか。というわけで、読んでいきたいと思います。

第12章 データの実装

この章での内容:

  • さまざまな方のオブジェクトがスタックに占めるバイト数を調べる方法
  • 外部モジュールで宣言された関数をアクセスするパスを短縮する方法
  • プリミティブ型のオブジェクトにビットがどう保存されるのか
  • オブジェクトがメモリのどこに保存されのかを調べる方法
  • パディングによって、ある種のオブジェクトが占めるサイズが増える理由
  • ベクターはどの様に実装されるのか

オブジェクトサイズ確認についてメモ

size_of 関数でオブジェクトサイズを確認します。&i8&i128 のようなリファレンスのサイズは、メモリアドレスのサイズです。

use std::mem::size_of;
println!("i8:{} i16:{} i32:{} i64:{} i128:{} bool:{} char:{} isize:{} usize:{} &i8:{} &i128:{}",
    size_of::<i8>(),
    size_of::<i16>(),
    size_of::<i32>(),
    size_of::<i64>(),
    size_of::<i128>(),
    size_of::<bool>(),
    size_of::<char>(),
    size_of::<isize>(),
    size_of::<usize>(),
    size_of::<&i8>(),
    size_of::<&i128>(),
);
i8:1 i16:2 i32:4 i64:8 i128:16 bool:1 char:4 isize:8 usize:8 &i8:8 &i128:8

メモリ上のバイト位置についてメモ

通常コードを書いている上でもは特にアドレスを意識することはないのかもしれません。ですが、厳密なルールも存在するので Rust
におけるメモリへの配置位置のルールについてです。

  • プリミティブ型のオブジェクトは、どれもそのサイズの整数倍となるアドレスに置かなければならない。

第13章 クロージャを定義する

この章での内容:

  • 引数と戻り値が型推論され、波括弧を書く必要がなく、関数定義の時点で生きていた変数をアクセスできる、という無名のインライン関数がなぜ必要なのか
  • そのような軽量関数 (クロージャ) を、どのようにすれば宣言して呼び出せるのか

クロージャについてメモ

クロージャの基本的な書き方は次のようになります。

|arg: T| -> T {
    expr_1;
    ...
    expr_n
};

クロージャは引数や戻り値の型が自明であれば省略できます。つまり、次のようなクロージャはすべて同じ意味になります。

  • 引数と戻り値の型を指定
let case1 = |x: u32| -> u32 { x + 1 };
  • 型を省略
let case2 = |x| { x + 1 };
  • 波括弧を省略
let case2 = |x| x + 1 ;

第14章 変更可能な文字列を使う

この章での内容:

  • 静的な文字列がどのように実装されるのか
  • 動的な文字列がどのように実装されるのか
  • 動的文字列で、どうすれば文字の追加や削除ができるのか
  • 静的文字列を動的文字列に、あるいはその逆に変換する方法
  • 複数の文字列を連結する方法

静的文字列についてメモ

次のように &str 型で定義している文字列は変更できない文字列で、静的文字列と呼ばれます。

let a: &str = "This is String.";

ちなみに、次のように書くとエラーが発生します。

let a: str = "This is String.";

[E0277] Error: the size for values of type str cannot be known at compilation time

コンパイル時には文字列のサイズを知ることが出来ないというエラーが発生します。

&str 型は str への参照なのですが、参照だけでなくポインタと長さのペアになっています。

動的文字列についてメモ

文字列を実行時に作成したり変更したりする場合には、静的文字列の &str を使用することができません。
そこで、動的文字列の String 型を使用します。

以下のような String 型の定義方法があります。

let a = String::from("Hello String");
let b = "Hello String".to_string();
let c = "Hello String".to_owned();
let d = format!("Hello String");

動的文字列の結合についてメモ

String 型の扱いはベクタに似ています。ベクタが持つ次のようなメソッドも実装されています。

  • push
  • pop
  • remove
  • insert
  • len
let a = "Hello".to_string();
let b = " ".to_string();
let c = "String".to_string();
let mut result = String::new();

result.push_str(&a);
result += &b;
result.push_str(&c);

println!("{}",result);

String 型文字列を結合する時に push で連結していますが、+= も使用できます。この +=push のシンタックスシュガーです。

Day 82 のまとめ

今日は 12 章のメモリ上のオブジェクトサイズ、 13 章のクロージャの使い方、そして 14 章の静的文字列動的文字列について読み進めてみました。

  • 第12章 データの実装
    • さまざまな方のオブジェクトがスタックに占めるバイト数を調べる方法
    • 外部モジュールで宣言された関数をアクセスするパスを短縮する方法
    • プリミティブ型のオブジェクトにビットがどう保存されるのか
    • オブジェクトがメモリのどこに保存されのかを調べる方法
    • パディングによって、ある種のオブジェクトが占めるサイズが増える理由
    • ベクターはどの様に実装されるのか
  • 第13章 クロージャを定義する
    • 引数と戻り値が型推論され、波括弧を書く必要がなく、関数定義の時点で生きていた変数をアクセスできる、という無名のインライン関数が なぜ必要なのか
    • そのような軽量関数 (クロージャ) を、どのようにすれば宣言して呼び出せるのか
  • 第14章 変更可能な文字列を使う
    • 静的な文字列がどのように実装されるのか
    • 動的な文字列がどのように実装されるのか
    • 動的文字列で、どうすれば文字の追加や削除ができるのか
    • 静的文字列を動的文字列に、あるいはその逆に変換する方法
    • 複数の文字列を連結する方法

あと 2 日で全部読み終えることできるかな。

GitHubで編集を提案

Discussion