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属性とは、マクロによってトレイトの既定の振る舞いを実装させることができる機能です。例えば Debug や PartialEq 、 Copy などがあります。
例えば、構造体動詞を == 演算子で比較する場合、 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


関連記事

rails

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

はじめに 最近、現在開発中のアプリケーションのステージング環境の構築を行なっています。 それにあたり、初めてCapistranoの設定を行いましたので、ここに設定した内容をまとめます。 注意点としては ...

rails

Ruby、Railsの時間に関するメソッドを使用してみた

はじめに 普段PHPのお仕事をしています、tonnyです。 半年程前からRuby on Railsの勉強を始めました。 今回はよく使う時間に関するメソッドついてまとめたいと思います。 目次 環境につい ...

rails

Rails Developer Meetup に参加してきました【1日目】

はじめに 3月24日、25日に開催された、Rails Developer Meetup に参加させていただきました。 多くの発表を聞くことができ、とても有意義な時間を過ごすことができました。 本日は、 ...

rails

Shrineでアップロードする際に画像を加工する

はじめに こんにちは、onoです。 前回、Shrineを使って画像をアップロードする方法を紹介しました。 今回は、アップロード時に画像を加工する方法を紹介します。   アップロードする画像の ...

rails

Shrineをモデルに関連付けないで使用してハマったこと

はじめに ShrineはRailsでのアップロードを簡単に行えるようにするGemです。 詳しくはこちらを御覧ください。 Shrineで画像をアップロードする処理を実装するなら、多くの場合モデルに関連付 ...

フォロー

blog-page_side_responsive

2023年4月
日 月 火 水 木 金 土
 1
2345678
9101112131415
16171819202122
23242526272829
30  

アプリ情報

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