ProgrammingRustバックエンド開発者

Rustにおけるメソッドと関連関数はどのように構成されていますか?それらの違い、宣言と呼び出しの仕方、そしてどの状況でどのバリエーションを使用すべきか教えてください。

Hintsage AIアシスタントで面接を突破

回答。

問題の歴史

Rustはオブジェクト指向言語からメソッドの概念を借用していますが、それを異なる方法で実装しています。従来のthisやselfではなく、メソッドは明示的にselfパラメータを受け取ります。関連関数は、他のプログラミング言語における静的メソッドの代わりに登場しました。これらは型に関連していますが、特定の値には関連していません。

問題

メソッド、関連関数、および自由関数を混同することがよくあります。selfを持つメソッドとselfを持たない関連関数をいつ使用するかが明確でありません。可視性、オートデレファレンス、所有権の移動に関する問題もあります。

解決策

Rustのメソッドは、implブロック内で最初のパラメータとしてself、&self、&mut selfを持つように宣言されます(通常はstructやenumに対して)。それらはインスタンスで呼び出されます:object.method()。関連関数(例えばnewやfrom)は、同様にimpl内で最初のパラメータselfを持たずに宣言され、二重コロンを介して呼び出されます:Type::function()

コード例:

struct Point { x: f64, y: f64, } impl Point { // 関連関数(コンストラクタ) fn new(x: f64, y: f64) -> Self { Self { x, y } } // メソッド:selfを要求 fn distance_from_origin(&self) -> f64 { (self.x.powi(2) + self.y.powi(2)).sqrt() } } let p = Point::new(3.0, 4.0); printf!("{}", p.distance_from_origin()); // 5.0

主な特徴:

  • メソッドは異なる所有権バリエーションのselfパラメータを受け取ります
  • 関連関数はselfを受け取らず、通常は初期化やユーティリティのために使用されます
  • メソッドはインスタンスでドット記法で呼び出されることができ、関連関数は::を介してのみ呼び出されます

トリッキーな質問。

関連関数をインスタンスから呼び出すことはできますか(ドット記法で)?

可能ですが(例えばp.new(1.0, 2.0))、非常に推奨されません。なぜなら、関連関数は現在のオブジェクトにアクセスできず、インスタンスが無視されて渡されるため、混乱を招くからです。Type::func()シンタックスを使用することをお勧めします。

コード例:

let p = Point::new(1.0, 2.0); let q = p.new(0.0, 0.0); // 動作するがベストプラクティスではない!

メソッドは非同期にすることができますか?

はい。メソッドは自由関数と同様に、asyncキーワードを使って宣言できます:

impl Foo { async fn do_async(&self) { // ... } }

同じimplブロック内でメソッドと関連関数の両方を宣言できますか?

はい—任意の組み合わせが許可されています。また、1つの型に対して複数のimplブロックを宣言することも可能です。

一般的なエラーとアAntiパターン

  • メソッドと関連関数を混同する
  • 型の所属を示さずに関連関数を残す(impl内で宣言しない)
  • インスタンスから関連関数を呼び出す(ドット記法で)

実生活の例

ネガティブケース

初心者がnew関数をimplの外で宣言し、それをコンストラクタとして使用しようとして、インスタンス経由で誤って呼び出しました:p.new(1.0, 2.0)

利点:

すぐに動作する(コンパイラが許可する)。

欠点:

コードが読みにくく、メンテナンスが困難で、正しいself所有権を持つメソッドを使用することが難しい。

ポジティブケース

すべてのメソッドと関連関数は厳密にimpl内で宣言され、呼び出しの正しいシンタックス(コンストラクタ用にType::new()、アクション用にobj.method())が使用されます。

利点:

高い可読性、ベストプラクティスに従っている。

欠点:

Rustのイディオムを知っている必要があり、シンタックスに注意が必要です。