BackEnd

Rust入門してみた (構造体 / トレイト)

投稿日:

はじめに

前回に引き続き、Rustの入門編です。今回は構造体とトレイトについて触れます。

構造体

Rustの構造体について見ていきます。

構造体の宣言は struct キーワードで始まり、カッコの中に、フィールド名と型を定義していきます。
インスタンスを作成するには、 User {} という形で、カッコ内にフィールド名と値を指定します。
構造体も変数と同じように、デフォルトでは不変であり、フィールドの中身を書き換えることもできません。フィールドの中身を書き換えるには、構造体の変数宣言時に mut キーワードを使用します。

ちなみに、不変のまま構造体の値を更新するには、構造体のインスタンス自体を作り直すことになりますが、その時に「構造体更新記法」を使用すると、コードを省略することができます。

メソッド

構造体にメソッドを定義するには、構造体を定義した後 impl User {} という形で、カッコの中に関数と似たシンタックスで定義していきます。まずは、コードを例示します。

各メソッドの第一仮引数には &self とします。このselfを経由して、自身のフィールドにアクセスすることができます。
また、自身のフィールドを変更する場合は &mut self とします。その場合、構造体そのものの変数定義時に、mutキーワードを使用する必要があります。

self として、所有権を奪うこともできます。

この場合、メソッドを呼び出すと呼び出すと所有権が移ってしまうため、その後インスタンスを再利用することはできません。
回避方法としては、関数の時と同じで、メソッドで return self することで所有権を返すか、インスタンスをcloneしてからメソッドを呼ぶことが考えられます。

関連メソッド

selfにアクセスする必要のない「関連メソッド」を定義することもできます。例えば、以下のようなものです。

Rustでの慣習で、自身のインスタンスを生成する関数は、 fn new() というように、関連メソッドで定義します。関連メソッドの呼び出しは、 User::new() という形で呼び出します。

トレイト

Rustでのトレイトは次のように trait キーワードを使って定義できます。先ほどのコードを変更してみます。

トレイトを宣言するには trait キーワードを使用し、かっこの中にメソッドを定義します。構造体がトレイトを実装するには、 impl トレイト名 for 構造体名 とし、かっこの中にトレイトで定義されているメソッドを実装します。

また、引数として受ける場合にトレイトを使用する場合には、 &impl トレイト名 として受けます。

このようにトレイトを使用することで、ポリモーフィズムを実現することができます。

構造体のフィールドの1つとして、トレイトのインスタンスを持つ場合

構造体のフィールドの1つとして、トレイトのインスタンスを持つ場合 dyn キーワードを使用します。また、合わせてBoxを使う必要があります。

Rustの構造体は、基本的にはコンパイル時に必要なデータサイズを計算できるようになっている必要があります。ですが、トレイトの場合は、実際に注入されるインスタンスの実装によって必要なデータサイズが異なるため、コンパイル時には必要なメモリ量を知ることができません。

そこで使用するのが、ヒープです。ヒープは、可変長データを扱うためのメモリ領域で、Boxを使うとヒープに実データを格納することができます。Box以外にも、VecやStringといった可変長データもヒープを使用します。

なぜ、コンパイル時に構造体に必要なデータサイズを知って置ける必要があるのでしょうか。それは、Rustでは基本的にスタック領域を使用するためです。スタック領域は、固定長のデータを扱うことができる代わりに、動作が高速です。
また、所有権システムを使用しているために、コンパイル時にスタックのデータ容量を計算することが可能になるのです。

対して、ヒープは可変長である代わりに、動作が低速です。そのため、必要な時にだけ使用するようにします。

Box自体は所有権システムによって管理されるため、スコープを抜けるとスタックに格納されているBoxと、ヒープに格納されているデータの両方が解放されます。
参考: Box<T>を使ってヒープにデータを格納する

スタックとヒープについては詳しくはこちらが参考になります。
https://blog.dcs.co.jp/rust/20201217-rust-5.html

dynについてはこちら
http://doc.rust-jp.rs/rust-by-example-ja/trait/dyn.html

derive属性

derive属性とは、マクロによってトレイトの既定の振る舞いを実装させることができる機能です。例えば DebugPartialEqCopy などがあります。
例えば、構造体動詞を == 演算子で比較する場合、 PartialEq のトレイトの実装が必要です。そのためには fn eq() メソッドを実装する必要がありますが、ほとんどの場合で全フィールドが等しい場合のみ等価、そうでなければ等価ではない、という実装になります。
このようなコードを毎回書くと冗長になってしまうため、derive属性によって、マクロによりコードを生成させることができます。

User構造体にderive属性を使って、DebugとPartialEqを実装しました。コードはマクロが生成してくれるので、実装コードを書く必要はありませんが、PartialEqによって比較や、Debugによって構造体のフィールドを出力できるようになっています。

おすすめ書籍

Webアプリ開発で学ぶ Rust言語入門 パーフェクトRust プログラミングRust 第2版

blog-page_footer_336




blog-page_footer_336




-BackEnd
-

執筆者:

免責事項

このブログは、記事上部に記載のある投稿日時点の一般的な情報を提供するものであり、投資等の勧誘・法的・税務上の助言を提供するものではありません。仮想通貨の投資・損益計算は複雑であり、個々の取引状況や法律の変更によって異なる可能性があります。ブログに記載された情報は参考程度のものであり、特定の状況に基づいた行動の決定には専門家の助言を求めることをお勧めします。当ブログの情報に基づいた行動に関連して生じた損失やリスクについて、筆者は責任を負いかねます。最新の法律や税務情報を確認し、必要に応じて専門家に相談することをお勧めします。


comment

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

CAPTCHA


関連記事

Go言語

Go言語の基礎〜基本構文その1〜

1 はじめに2 変数2.1 変数の定義2.2 暗黙的な定義2.3 varと暗黙的な定義2.4 ローカル変数とパッケージ変数3 定数3.1 const3.2 iota4 関数4.1 関数定義の基本4.2 ...

Go言語

Goのクエリビルダー goqu を使ってみる

1 はじめに2 goquとは2.1 対応するDB3 基本的な使い方3.1 Insert句を生成する3.2 Select句を生成する3.3 Update句を生成する3.4 Delete句を生成する4 よ ...

laravel logo

Inertia使ってみた①

1 はじめに2 Inertiaとは3 ルーティング4 LaravelからReactに値渡し5 レスポンス5.1 初回5.2 page object5.3 2回目以降5.4 リロード時6 さいごに7 お ...

rails

Capistrano3でRailsアプリケーションをデプロイする

1 はじめに1.1 前提条件2 Cpistranoについて3 導入3.1 Gemのインストール3.2 設定ファイルの準備4 デプロイ設定4.1 Capfileを修正する4.2 各環境で共通のデプロイ設 ...

laravel logo

Laravelのコントローラの基礎

1 はじめに2 ルーティング2.1 使用可能なメソッド2.2 リダイレクト2.3 Viewの返却2.4 ルートパラメータ2.5 ミドルウェア2.6 プレフィックス3 バリデーション3.1 コントローラ ...

フォロー

blog-page_side_responsive

2023年4月
 1
2345678
9101112131415
16171819202122
23242526272829
30  

アプリ情報

私たちは無料アプリもリリースしています、ぜひご覧ください。 下記のアイコンから無料でダウンロードできます。