RUST言語の「参照」を調べてみた No-R001

2024年8月25日blender

 事の始まりは、工房の部屋が湿気が多く、いろいろ電子機器への湿気の影響があってトラブルが多い部屋から始まる。

去年から今までに3回キーボードを買い替えて、さすがに3回目ともなると「また壊れたら阿保らしいから安いヤツで様子見」とあえて、価格の安い「有線USSBキーボード」を購入。ただし、個人的に気になっていたキータッチ感がすばらしい「メカニカルキ」のキーボードを購入しておいた。

 このキーボードのタッチ感がすばらしくて、ひさしぶりにプログラミングでもと始めたのが、RUST言語なのです。

ここで参考サイトを。

Introduction – Rust By Example 日本語版 (rust-jp.rs)

 備忘録的によく見るサイトに「とほほ」のシリーズに「とほほのRUST入門」のURLを。概要確認にはシンプルでありがたい。

とほほのRust入門 – とほほのWWW入門 (tohoho-web.com)

もうひとつ入門向けの書籍(Webで公開)を記す

https://zenn.dev/mebiusbox/books/22d4c1ed9b0003/viewer/6d5875

読み進むと「参照型(&, *)」というのがあり、C言語でいうとこの「ポインタ」であるようです。

懐かしい。ポインタ。はじめてのCやK&RのC言語本でアドレスを参照する書き方なだと知ってもう半世紀近い。じじいになったものです。(現在57歳)

さて今日も少々RUSTのサンプルプログラムを試して新しい言葉に出会ったので備忘録。

「参照型」と「所有権・移動・参照・借用」と続きます。

なにやらCやC++で見た言語仕様のようなイメージが続きます。そのなかで気になった言葉がこれ。

「トレイト」

スポンサーリンク

トレイト(Trait)

「データ型を分類する概念」

トレイトとは任意の型であるSelfに対してメソッドを定義でき、共通の振る舞いを実装できる機能だそうで。かつ、「任意の型=あらゆるデータ型」に実装することができ、多言語のインターフェースや抽象クラスのような役割を果たす。

ここでRUSTは「オブジェクト指向」の言語では明確にいうと違うらしいが、オブジェクト指向言語にでてくる言葉が続きます。

試したサンプルコードがこちら。

往年のプログラマーさんには、「アスタリスク:*」と「アンド:&」 *と& にはわくわくするものがありますよね。

そうです。C言語のポインタにかかわる記述法と似ています。

C言語におけるポインタは、コンピューターのメモリ空間を「見る・参照する・書き換える」ことを実装した記述法をまとめてポインタという言い方をしています。

さらに絞って書くと、「C言語のポインタ=メモリ空間の1アドレスそのもの」と理解しています。

ここでもう少しメモリ空間を詳しく。

現在のパソコンは16Gメモリと膨大すぎるメモリ空間です。え?それがどうした?

過去、パソコン聡明期には、Z80CPUという名機が存在しており、NECの名機 PC8801やMZ80Bといった傑作機がありました。

そのメモリ空間は、64KB(キロバイト)というものでした。

単位を説明すると。

半角英数文字1文字のデータ量が「1バイト」です。

1024バイト=1キロバイト、1024キロバイト=1メガバイト、1024メガバイトが1ギガバイトということになります。

1KB(キロバイト)=1024バイト
1MB(メガバイト)=1024KB(約100万バイト)
1GB(ギガバイト)=1024MB(約10億バイト)
1TB(テラバイト)=1024GB(約1兆バイト)

いまのパソコンは、4GBまたは8GBがメインでしょう。

1バイトが半角英数字1文字 1バイト=1文字ですから、64KB=64K文字ということです。

ここからもう少し具体的に。というか難しくなります。

アドレス=番地 そう番地なんです。住所なです。

10KBであれば、そのファイルが10240バイトの容量 「10240個の住所=アドレスを持つ」となります。

ただし、この1バイト=8ビット(BIT)なので注意が必要です。それは「型」で大きさが違うのです。

プログラム言語では型が重要です。

 基本データ型

Rust  データ型

  • 整数型: i8u8i16u16i32u32i64u64isizeusize
  • 浮動小数点型: f32f64
  • ブーリアン型: bool
  • 文字列型: char
  • タプル(複合)型: (500, 6.4, true)() はユニット.
  • 配列型: [1,2,3,4,5][3;5] = [3,3,3,3,3]

数値型のリテラル(データ型の値を直に記載したもの)

  • 123456 (10進数)
  • 0xfa (16進数)
  • 0o55 (8進数)
  • 0b10000(2進数)
  • b'A' (バイト)
  • 2.5 (浮動小数点数)

2進数の定数

例えば、2進数の定義 

サンプルは数字「16」を2進数として定義するには、0bプレフィックスを使用します。以下にサンプルコードを示します。

fn main() {
    const SIXTEEN: u32 = 0b10000;
    println!("The value of SIXTEEN in binary is: {:b}", SIXTEEN);
}

表示(コンソール):
The value of SIXTEEN in binary is: 10000

このコードでは、SIXTEENという名前の定数を2進数表記で定義し、その値を0b10000に設定しています。println!マクロを使って、その値を2進数表記で出力しています。

整数の定数

16を整数として定義するには、constキーワードを使用します。

fn main() {
    const SIXTEEN: i32 = 16;
    println!("The value of SIXTEEN is: {}", SIXTEEN);
}

このコードでは、SIXTEENという名前の定数をi32型で定義し、その値を16に設定しています。

文字のバイト表記=バイトリテラル

文字 A をバイトリテラルとして定義するには、b'A' という表記を使用します。

fn main() {
    const BYTE_A: u8 = b'A';
    println!("The value of BYTE_A is: {}", BYTE_A);
}
表示(コンソール):
The value of BYTE_A is: 65

このコードでは、BYTE_A という名前の定数を u8 型で定義し、その値をバイトリテラル b'A' に設定しています。

Rustで浮動小数点数を定義し、基本的な演算を行うサンプルコード

浮動小数点の定義について

fn main() {
    // f32型の浮動小数点数を定義
    let a: f32 = 3.5;
    let b: f32 = 2.0;

    // 足し算
    let sum = a + b;
    println!("{} + {} = {}", a, b, sum);

    // 引き算
    let difference = a - b;
    println!("{} - {} = {}", a, b, difference);

    // 掛け算
    let product = a * b;
    println!("{} * {} = {}", a, b, product);

    // 割り算
    let quotient = a / b;
    println!("{} / {} = {}", a, b, quotient);

    // 余り(浮動小数点数では通常使用しませんが、整数にキャストして使用可能)
    let remainder = (a as i32) % (b as i32);
    println!("{} % {} = {}", a as i32, b as i32, remainder);
}

Rustでは、浮動小数点数は主に2つの型で表現されます:f32(32ビット浮動小数点数)とf64(64ビット浮動小数点数)です。これらはそれぞれ単精度と倍精度の浮動小数点数を表します。

  • f32: 単精度浮動小数点数で、符号部1ビット、指数部8ビット、仮数部23ビットで構成されています。
  • f64: 倍精度浮動小数点数で、符号部1ビット、指数部11ビット、仮数部52ビットで構成されています。

Rustでは、浮動小数点数の計算はIEEE 754規格に準拠しており、精度とパフォーマンスのバランスが取れています。

ここでアドレスとは

Rustにおけるメモリ管理とポインタの使い方について説明します。

メモリ空間

Rustでは、メモリは主にスタックヒープの2つの領域に分かれています。

  • スタック: 関数呼び出しやローカル変数のために使用されるメモリ領域です。スタックはLIFO(Last In, First Out)方式で管理され、アクセスが非常に高速です。スタックに置かれるデータは、関数のスコープを抜けると自動的に解放されます。
  • ヒープ: 動的に確保されるメモリ領域で、サイズが不定のデータ(例:ベクタや文字列)に使用されます。ヒープへのアクセスはスタックよりも遅いですが、より大きなデータを扱うことができます。ヒープに確保されたメモリは、所有権のルールに従って管理されます。

Rustにおける&*の使い方について詳しく説明します。

Rustでは、ポインタの代わりに参照を使用します。参照は、メモリ上のデータへのアクセスを提供しますが、所有権を持ちません。参照は&記号を使って作成され、デリファレンス(参照外し)には*記号を使います。

&(参照)

&は変数が指し示す値への参照を作成します。参照は、所有権を持たずにデータにアクセスするための方法です。これにより、データのコピーを避け、効率的にメモリを使用できます。

例: 参照の作成

fn main() {
    let x = 10;
    let y = &x; // xへの参照を作成
    println!("y = {}", y); // yはxを指しているので、10が出力される
}

この例では、yxの参照です。yを使ってxの値にアクセスできますが、yxの所有権を持ちません。

*(デリファレンス)

*は参照が指し示す値にアクセスするために使用されます。これをデリファレンスと呼びます。デリファレンスを行うことで、参照が指している実際の値を取得できます。

例: デリファレンス

fn main() {
    let x = 10;
    let y = &x; // xへの参照を作成
    let z = *y; // yをデリファレンスしてzに値をコピー
    println!("z = {}", z); // zは10
}

この例では、yxの参照であり、*yxの値(つまり10)を指します。z*yを代入することで、zxの値を持つことになります。

まとめ

  • &は参照を作成し、変数が指し示す値へのアクセスを提供します。
  • *は参照をデリファレンスし、参照が指し示す値にアクセスします。

これらの機能を使うことで、Rustでは安全かつ効率的にメモリを管理し、データの所有権やライフタイムを明確にすることができます。

スマートポインタ

Rustには、メモリ管理を簡素化するためのスマートポインタがいくつかあります。代表的なものにはBox<T>Rc<T>Arc<T>RefCell<T>があります。

  • Box<T>: ヒープにデータを格納し、所有権を持つスマートポインタです。スコープを抜けると自動的にメモリが解放されます。
  • Rc<T>: 参照カウント方式で複数の所有者を持つことができるスマートポインタです。スレッドセーフではありません。
  • Arc<T>Rc<T>のスレッドセーフ版で、複数のスレッド間で所有権を共有できます。
  • RefCell<T>: 不変オブジェクトを内部的に可変にすることができるスマートポインタです。

Rustのスマートポインタは、通常の参照のように使えるだけでなく、追加のメタデータと機能を持つデータ構造です。

主なスマートポインタの種類

  1. Box<T>
    • 用途: ヒープにデータを格納し、所有権を持つスマートポインタです。
    • 特徴: スタックに置けない大きなデータや再帰的なデータ構造を扱う際に使用されます。
    Rustfn main() { let x = Box::new(5); println!("x = {}", x); }
  2. Rc<T>
    • 用途: 参照カウント方式で複数の所有者を持つことができるスマートポインタです。
    • 特徴: シングルスレッド環境で共有所有権を持つデータを扱う際に使用されます。
    Rustuse std::rc::Rc; fn main() { let a = Rc::new(5); let b = Rc::clone(&a); println!("a = {}, b = {}", a, b); }
  3. Arc<T>
    • 用途Rc<T>のスレッドセーフ版で、複数のスレッド間で所有権を共有できます。
    • 特徴: マルチスレッド環境で共有所有権を持つデータを扱う際に使用されます。
    Rustuse std::sync::Arc; use std::thread; fn main() { let a = Arc::new(5); let b = Arc::clone(&a); let handle = thread::spawn(move || { println!("b = {}", b); }); println!("a = {}", a); handle.join().unwrap(); }
  4. RefCell<T>
    • 用途: 不変オブジェクトを内部的に可変にすることができるスマートポインタです。
    • 特徴: 実行時に可変性をチェックし、シングルスレッド環境での内部可変性を提供します。
    Rustuse std::cell::RefCell; fn main() { let x = RefCell::new(5); *x.borrow_mut() += 1; println!("x = {}", x.borrow()); }

スマートポインタのトレイト

  • Derefトレイト: 参照外し演算子(*)の挙動を定義します。これにより、スマートポインタを通常の参照のように扱うことができます。
  • Dropトレイト: スコープを抜けるときにリソースを解放するための挙動を定義します。

スマートポインタを使うことで、Rustでは安全かつ効率的にメモリ管理を行うことができます。

/// PR /// 

かつてパソコン黎明期に「ナイコン」という言葉がありました。パソコンが無くて電気店に展示しているパソコンを自由につかってプログラミングしてカセットテープに録音して(音声でプログラムを保存)していました。そのとき小学生がどこの店舗にもかならずいて有名(スキルがあるという意味で)でした。

そう。そういう人たちが大人になってIT業界で伝説を作ってきた時代がいままた到来していますね。

/// PR ///

ところで、電気代金が気になる夏の時期(記事を書いてるのは8月後半)もちろんクーラーだけでなくパソコンも毎日稼働、かつ高性能(ここのユーザーさんは高スペックなPC持ちと想像してます)だとけっこうな電気料金。

東京電力・北海道電力などでしたら3割値引きのプランを紹介している記事でした。ごらんください。いまなら3か月無料キャンペーンだそうです。

—————————————————————————————————————

//// PR ///

youme mobile でスマホ永年無料になる方法が公開されています。いまだけ(3万人限定)で年間スマホ基本料金8万~10万をタダにしましょう! これはyoume mobile が既存ユーザーからの招待制によって契約出来るのでぜひ一度ごらんください。

※ 申し込みボタンで紹介コード付状態になりますので、登録が簡単です。

————————————————————————————————————–

//// PR /// 弊工房オフィシャルネットショップ(スズリ)です。ぜひご来店ください。

//// PR ///

//// PR /// 弊工房オフィシャルネットショップ(BASE)です。ぜひご来店ください。

ここでは著者が運営しているミリタリー工房 猫・工・艦で展開しているグッズアイテムを紹介させていただきます。

https://necokoucan.thebase.in/

————————————————————————————————————–

過去記事は下記を参照ください。2013年からミリタリー同人活動を行っています。

サイトマップ | ミリタリーグッズ工房「猫・工・艦」 (necokoucan.com)

【ブログ記事一覧】 | ミリタリーグッズ工房「猫・工・艦」 (necokoucan.com)

ミリタリーランキング
ブログランキング・にほんブログ村へにほんブログ村

blender

Posted by necogiji