導入文章
Rustは、プログラムのコードを整理し、管理するためにモジュールシステムを提供しています。このシステムでは、異なるモジュール間でコードを共有するためにアクセス修飾子を使用して、コードの公開範囲を細かく制御することができます。中でもpub(crate)
は、クレート内部でモジュールやアイテムの可視性を管理するための強力なツールです。pub(crate)
は、アイテムをクレート内でのみ公開し、外部からのアクセスを制限することができます。このアクセス制御を活用することで、コードのカプセル化が強化され、他のモジュールとの依存関係をしっかり管理できます。本記事では、pub(crate)
の使い方、利点、注意点、さらには実際の活用事例について詳しく解説します。
Rustのモジュールシステムとは
Rustのモジュールシステムは、コードを整理し、複雑なプロジェクトを構造的に管理するための強力な仕組みです。モジュールを使うことで、プログラムの機能を論理的に分割し、コードの可読性と再利用性を高めることができます。
モジュールの基本概念
Rustでは、モジュールを使ってプログラムをグループ化します。モジュールは、クレート内に含まれる各機能を分離し、それらを整理するための基本的な単位です。モジュールは、mod
キーワードを使って宣言します。例えば、mod my_module;
のように書くことで、my_module
というモジュールを定義できます。モジュールは、別のファイルに分けて定義することもできます。
モジュールの階層
Rustでは、モジュールを階層的に定義することもできます。例えば、mod my_module;
の中にさらにサブモジュールを定義することができます。このように、モジュールをネストすることで、大規模なプロジェクトでも構造を保ちながら整理できます。
モジュール間でのアクセス制御
Rustでは、モジュール間でのアクセス制御を厳密に管理できます。これにより、クレート内部のコードが外部に公開される範囲を制御することができます。pub
やprivate
などのアクセス修飾子を使って、モジュールや関数、構造体、変数などの可視性を設定できます。これにより、必要に応じてコードの公開範囲を細かく制御し、モジュール間の依存関係を管理できます。
モジュールシステムをうまく活用することで、コードの整理や拡張性の向上が可能となり、より効率的なソフトウェア開発が実現できます。
アクセス修飾子の種類
Rustでは、モジュールやその内部のアイテムに対するアクセス制御を細かく設定できるアクセス修飾子が用意されています。これにより、外部からアクセス可能な部分と内部でのみ利用する部分を明確に分けることができ、プログラムのカプセル化やセキュリティを強化できます。代表的なアクセス修飾子には、pub
、private
、およびpub(crate)
などがあります。それぞれの修飾子がどのように機能するのかを解説します。
`pub`修飾子
pub
は、アイテムを外部に公開するための最も一般的な修飾子です。モジュール内の関数や構造体、フィールド、メソッドなどにpub
をつけることで、そのアイテムをクレート外からもアクセスできるようにします。例えば、モジュール内で次のように定義された関数は、外部からもアクセス可能です。
pub fn my_function() {
println!("This function is public!");
}
この関数は、他のクレートからも呼び出せるようになります。pub
を使用することで、クレート外のコードとインターフェースを公開できますが、外部からのアクセスを許可することにより、設計の自由度が制限される場合もあるため、使用には注意が必要です。
`private`修飾子
Rustでは、デフォルトでモジュールやアイテムはプライベートです。つまり、特に修飾子を付けなければ、そのアイテムは同じモジュール内でのみアクセス可能となります。private
はその明示的な修飾子として使われることは少なく、通常は省略されますが、モジュール内で隠蔽したい部分を意図的に非公開にするために使われます。
例えば、次の関数は同じモジュール内でのみ使用できます:
fn my_private_function() {
println!("This function is private!");
}
この関数は、同じモジュール内でしか呼び出すことができません。他のモジュールやクレートからはアクセスできません。
`pub(crate)`修飾子
pub(crate)
は、アイテムをクレート内でのみ公開するための修飾子です。これを使用することで、クレート外部からはアクセスできないものの、同一クレート内の他のモジュールからはアクセス可能にすることができます。この修飾子は、特定のモジュール間でコードを共有しつつ、クレート外部からはアクセスさせたくない場合に便利です。
例えば、次のようにpub(crate)
を使った関数は、同じクレート内であれば他のモジュールからアクセスできますが、クレート外部からはアクセスできません:
pub(crate) fn my_crate_function() {
println!("This function is public within the crate!");
}
このように、pub(crate)
を使用することで、クレートの内部でのみ利用されるべきアイテムを安全に公開し、外部からは隠蔽できます。
アクセス修飾子の使い分け
pub
: クレート外部からアクセス可能、外部公開が必要な場合に使用。private
: 同じモジュール内でのみアクセス可能、隠蔽したい場合に使用(デフォルト)。pub(crate)
: クレート内でのみアクセス可能、クレート内部での共有が必要な場合に使用。
これらのアクセス修飾子を適切に使い分けることで、コードの公開範囲を制御し、設計の意図を明確にすることができます。
`pub(crate)`の使い方
pub(crate)
は、Rustでモジュールやアイテムをクレート内で公開するためのアクセス修飾子です。この修飾子を使うことで、クレート外からはアクセスできないようにしつつ、クレート内部では他のモジュールからアクセス可能にすることができます。pub(crate)
の使用方法について、実際のコード例とともに詳しく解説します。
基本的な使い方
pub(crate)
は、関数、構造体、列挙型、モジュールなど、Rustのあらゆるアイテムに適用できます。これを使うと、指定したアイテムは同じクレート内の他のモジュールからはアクセスできるようになり、クレート外からはアクセスできなくなります。
例えば、次のようにモジュール内で関数を定義し、その関数にpub(crate)
を付けることで、クレート内の他のモジュールからアクセス可能になりますが、クレート外からはアクセスできなくなります。
// src/my_module.rs
pub(crate) fn my_crate_function() {
println!("This function is public within the crate!");
}
この関数は、my_module
内で定義されており、pub(crate)
によって、同じクレート内の他のモジュールから呼び出すことができます。しかし、クレート外のコードからはアクセスできません。
モジュールでの使用例
pub(crate)
はモジュール自体にも適用できます。例えば、あるモジュールがクレート内で共有されるべきだけど、外部には公開したくない場合に、モジュールをpub(crate)
で公開することができます。
// src/my_module.rs
pub(crate) mod internal_module {
pub fn my_internal_function() {
println!("This function is public within the crate!");
}
}
このコードでは、internal_module
というサブモジュールをクレート内で公開し、内部からアクセスできるようにしていますが、外部からはアクセスできません。my_internal_function
はinternal_module
内で呼び出すことができますが、クレート外部からはアクセスできません。
構造体や列挙型での利用
pub(crate)
は、構造体や列挙型にも適用可能です。例えば、特定の構造体をクレート内でのみアクセス可能にしたい場合、次のように書きます。
// src/my_module.rs
pub(crate) struct MyStruct {
pub(crate) name: String,
pub(crate) age: u32,
}
impl MyStruct {
pub(crate) fn new(name: String, age: u32) -> Self {
MyStruct { name, age }
}
}
このMyStruct
は、同じクレート内の他のモジュールから使用可能ですが、外部クレートからはアクセスできません。name
やage
といったフィールド、またnew
メソッドもpub(crate)
によってクレート内でのみ使用可能となります。
関数と構造体を組み合わせた例
さらに実用的な例として、クレート内でのみ使いたい関数と構造体を組み合わせたコードを見てみましょう。次の例では、MyStruct
という構造体とそのメソッドを使って、クレート内でのみ利用できるようにしています。
// src/my_module.rs
pub(crate) struct MyStruct {
pub(crate) name: String,
}
impl MyStruct {
pub(crate) fn new(name: String) -> Self {
MyStruct { name }
}
pub(crate) fn greet(&self) {
println!("Hello, {}!", self.name);
}
}
この例では、MyStruct
をpub(crate)
でクレート内で公開し、greet
メソッドもクレート内でのみ呼び出せるようにしています。この構造体とそのメソッドは、クレート内での利用に制限され、クレート外部からはアクセスできません。
アクセス制限を意識した設計
pub(crate)
は、クレート内で公開したいけれども外部からは隠蔽したいコードに適しています。例えば、ライブラリの内部で使うユーティリティ関数やヘルパー関数、クレート内でしか利用しないモジュールや構造体をpub(crate)
で公開することで、外部に公開すべきでない部分を隠すことができます。これにより、外部のコードとのインターフェースを明確にし、誤って内部の詳細にアクセスされることを防ぐことができます。
pub(crate)
を適切に使うことで、Rustのカプセル化とコードのモジュール化をさらに強化し、クレートの設計をより堅牢にできます。
`pub(crate)`を使う利点
pub(crate)
は、Rustのアクセス制御において非常に有用なツールであり、クレート内でのカプセル化とモジュール間の整理に大きな利点をもたらします。ここでは、pub(crate)
を使用することによる主要な利点をいくつか紹介します。
1. クレート内のカプセル化を強化
pub(crate)
を使用することで、クレート内の特定のコードを内部利用に限定し、外部からのアクセスを防ぐことができます。これにより、クレート内部の詳細な実装が外部から見えなくなり、設計が堅牢になります。クレートの公開インターフェース(pub
修飾子を使って外部に公開したアイテム)と内部実装の間に明確な境界線を引くことができ、クレートの利用者が内部の実装に依存することを防ぎます。
例えば、ある関数や構造体をpub(crate)
で公開することで、他のモジュールや内部のテストコードからはアクセスできる一方、クレート外からは見えなくなります。これにより、クレート外のユーザーが無理に内部の詳細に依存することを避け、モジュールの保守性が向上します。
2. 不要な公開範囲を避ける
pub(crate)
を使うことで、必要以上にアイテムを公開せずに、最小限の公開範囲で済ますことができます。クレート内でのみ使用されるコードを公開することで、コードのインターフェースを最小化でき、無駄な公開範囲を避けることができます。
例えば、特定のヘルパー関数や内部構造体を外部からアクセスできないようにすることで、APIがシンプルになり、誤って使用されるリスクを減らせます。これにより、クレートの使い方がより明確になり、誤解を避けることができます。
3. テストコードのアクセス制御
テストコード内では、pub(crate)
を使って内部のアイテムにアクセスすることができます。テストコードがクレートの内部実装を検証するために使用される場合、pub(crate)
は非常に便利です。外部からのアクセスを制限しつつ、テスト対象のコードをクレート内で利用できるため、クレートの機能を十分にテストすることが可能です。
例えば、内部でのみ利用する関数や構造体をpub(crate)
で公開し、テストコード内からその動作をチェックすることができます。これにより、外部ユーザーには見せたくないコードを適切にテストできるようになります。
4. 冗長な公開を避けることでセキュリティ向上
公開する範囲を最小限に抑えることで、クレートが外部に提供するインターフェースをシンプルに保ち、セキュリティ面でも利点があります。クレート内のすべてのアイテムを無条件でpub
として公開することは、意図しないアクセスや誤用のリスクを高める可能性がありますが、pub(crate)
を使うことで、このリスクを抑え、必要な部分だけを公開できます。
特に、外部に公開したくない実装の詳細部分や、セキュリティ上重要な部分を隠蔽する際にpub(crate)
は非常に有効です。例えば、認証やセキュリティ関連のコードを内部に保持し、外部からアクセスできないようにすることができます。
5. モジュール設計の柔軟性
pub(crate)
を使うことで、モジュール間の依存関係を柔軟に設計できます。クレート内でモジュール同士が連携して動作する場合、特定のモジュールのアイテムをpub(crate)
で公開しておけば、他のモジュールからはアクセスできるようになりますが、外部のクレートからは直接利用できなくなります。
これにより、モジュール間で密接に結びついた機能を提供しつつ、外部からはその詳細を隠蔽して、外部APIを安定的に保つことができます。複雑なプロジェクトやライブラリにおいて、モジュールの設計をより直感的で安全に行うことが可能になります。
まとめ
pub(crate)
は、Rustにおけるアクセス制御を強化するための重要なツールであり、クレート内でのみ公開したいアイテムに最適です。この修飾子を使用することで、コードのカプセル化が強化され、不要な公開を避けることができ、テストコードやセキュリティ向上にも貢献します。pub(crate)
を上手に活用することで、コードの保守性や可読性が向上し、安全で効率的なソフトウェア開発が実現します。
実際のコード例:`pub(crate)`の活用
ここでは、pub(crate)
を活用した実際のコード例をいくつか紹介し、その使い方をより具体的に理解できるようにします。これにより、pub(crate)
がどのようにモジュール内で機能し、クレート外とのインターフェースにどのように影響を与えるかを学びます。
例1: モジュール内での`pub(crate)`の使用
以下のコード例では、pub(crate)
を使って、クレート内でのみアクセス可能な関数を定義し、外部からのアクセスを制限しています。
// src/lib.rs
mod internal_module {
pub(crate) fn internal_function() {
println!("This function is visible only within the crate.");
}
pub(crate) struct MyStruct {
pub(crate) field: String,
}
impl MyStruct {
pub(crate) fn new(field: String) -> Self {
MyStruct { field }
}
pub(crate) fn greet(&self) {
println!("Hello, {}!", self.field);
}
}
}
fn main() {
// クレート内でのみアクセス可能
internal_module::internal_function();
let my_struct = internal_module::MyStruct::new("Rust".to_string());
my_struct.greet();
}
このコードでは、internal_module
内でpub(crate)
を使い、internal_function
やMyStruct
、そのメソッドをクレート内でのみ使用できるようにしています。internal_function
やMyStruct
は、同じクレート内ではアクセスできますが、外部のコードからはアクセスできません。
例2: クレート内のテストコードでの`pub(crate)`使用
Rustのテストモジュールでは、pub(crate)
を使うことで、テスト専用の関数や構造体にアクセスすることができます。以下は、テストコードから内部アイテムにアクセスする例です。
// src/lib.rs
mod internal_module {
pub(crate) fn add_two(a: i32) -> i32 {
a + 2
}
pub(crate) struct MyStruct {
pub(crate) value: i32,
}
impl MyStruct {
pub(crate) fn new(value: i32) -> Self {
MyStruct { value }
}
pub(crate) fn double(&self) -> i32 {
self.value * 2
}
}
}
// テストモジュール
#[cfg(test)]
mod tests {
use super::internal_module;
#[test]
fn test_add_two() {
let result = internal_module::add_two(3);
assert_eq!(result, 5);
}
#[test]
fn test_double() {
let my_struct = internal_module::MyStruct::new(5);
assert_eq!(my_struct.double(), 10);
}
}
このコードでは、add_two
関数やMyStruct
のdouble
メソッドにpub(crate)
を使用し、テストモジュール内からそのアイテムを利用しています。テストコード内では、クレート内の非公開アイテムにアクセスできるので、内部のロジックを検証することができます。しかし、これらのアイテムは外部のコードからはアクセスできません。
例3: 外部に公開する関数と内部専用の関数
次に、外部に公開する関数と内部専用の関数を組み合わせた例を紹介します。クレートの外部に公開するインターフェースと、内部でのみ利用する詳細な実装を分ける方法です。
// src/lib.rs
mod internal_module {
pub(crate) fn private_helper() {
println!("This is a helper function for internal use.");
}
pub fn public_function() {
println!("This function is available outside the crate.");
private_helper(); // 内部関数を呼び出す
}
}
fn main() {
// 外部からはpublic_functionのみアクセス可能
internal_module::public_function();
// 以下のコードはエラーになる
// internal_module::private_helper(); // エラー: private_helperはクレート内でしか使用できません
}
この例では、public_function
が外部に公開されており、private_helper
関数はpub(crate)
でクレート内に限定されています。public_function
内からはprivate_helper
を呼び出していますが、外部からは直接アクセスできません。
例4: サブモジュールでの`pub(crate)`の活用
クレート内で複数のサブモジュールを使う場合、pub(crate)
を使って各モジュール間でのアクセスを管理できます。例えば、外部には公開したくないけれど、クレート内の他のモジュールにはアクセスさせたいアイテムをpub(crate)
で公開する方法です。
// src/lib.rs
pub(crate) mod internal {
pub(crate) fn helper_function() {
println!("This helper function is accessible only within the crate.");
}
}
mod external {
// `internal::helper_function`にアクセス
pub fn use_helper() {
crate::internal::helper_function();
}
}
fn main() {
// クレート外部からはアクセスできない
// internal::helper_function(); // エラー: クレート外からアクセスできません
external::use_helper(); // クレート内からはアクセス可能
}
このコードでは、internal
モジュール内のhelper_function
をpub(crate)
で公開し、同じクレート内のexternal
モジュールからアクセス可能にしています。しかし、クレート外部からはこの関数にはアクセスできません。
まとめ
これらの実例を通して、pub(crate)
がどのように機能するかを学びました。pub(crate)
は、クレート内で共有したいけれども外部には公開したくないアイテムを安全に管理するための非常に有用なツールです。特に、モジュール間でのアクセスを柔軟に管理したり、テストコード内で内部アイテムにアクセスしたりする際に効果的です。
`pub(crate)`と`pub`の違い
Rustでは、アクセス制御を行うためにpub
やpub(crate)
などの修飾子が使われますが、これらの違いを理解することは非常に重要です。ここでは、pub
とpub(crate)
の主な違いを説明し、どの状況でどちらを使用すべきかを考えます。
`pub`の意味と使用方法
pub
は最も広範囲に公開されるアクセス修飾子で、クレート外部からもアクセスできるようにします。外部のクレートやモジュールから、そのアイテムにアクセスできるようになります。これにより、ライブラリのAPIや外部とのインターフェースを定義する際に使用されます。
例えば、以下のコードでは、pub
を使ってクレート外からもアクセス可能な関数を定義しています。
// src/lib.rs
pub fn public_function() {
println!("This is a public function, accessible outside the crate.");
}
この関数は、同じクレート内だけでなく、他のクレートからも呼び出すことができます。
`pub(crate)`の意味と使用方法
一方で、pub(crate)
はそのアイテムをクレート内でのみ公開します。外部のクレートからはアクセスできませんが、クレート内の他のモジュールやテストコードからはアクセス可能です。これは、クレート内部でのみ利用するが、モジュール間で共有したいアイテムに適用されます。
// src/lib.rs
pub(crate) fn crate_only_function() {
println!("This function is only accessible within the crate.");
}
この関数は、同じクレート内では呼び出すことができますが、外部のコードやクレートからはアクセスできません。
主な違い
- 公開範囲:
pub
はクレート外部にも公開される。pub(crate)
はクレート内でのみ公開され、外部からアクセスできない。- 用途:
pub
はライブラリやAPIのインターフェースとして外部に公開する場合に使用します。pub(crate)
はクレート内でのモジュール間の共有やテストコードでの利用に適しています。外部には公開したくないが、クレート内でアクセスする必要がある場合に便利です。
実際の使い分け例
例えば、外部APIとして提供する関数はpub
を使い、内部的に利用するヘルパー関数や構造体はpub(crate)
を使うと良いでしょう。
// 外部に公開したいAPI
pub fn public_api_function() {
println!("This is an API function accessible externally.");
}
// クレート内でのみ利用したい内部ヘルパー関数
pub(crate) fn internal_helper() {
println!("This helper function is used internally within the crate.");
}
この場合、public_api_function
は他のクレートからも利用可能で、internal_helper
はクレート内でのみ利用されます。
まとめ
pub
とpub(crate)
の主な違いは、公開範囲にあります。pub
は外部に公開されるアクセス修飾子であり、pub(crate)
はクレート内でのみアクセス可能です。Rustの設計哲学において、外部に公開するべきものと、クレート内部でのみ利用すべきものを適切に分けることが、コードの保守性やセキュリティ向上につながります。
ベストプラクティス:`pub(crate)`の効果的な使用法
pub(crate)
は、Rustのアクセス制御の中で強力なツールですが、効果的に使用するためには適切な設計と判断が求められます。ここでは、pub(crate)
を使う上でのベストプラクティスをいくつか紹介します。これらを実践することで、Rustのコードがより安全で効率的に管理できるようになります。
1. 公開範囲を最小化する
アクセス制御の基本的な原則の一つは、「公開範囲を最小化する」ことです。pub(crate)
は、外部には公開せず、クレート内での利用に制限するため、不要な公開を避けるのに非常に有用です。内部でのみ使用する関数や構造体をpub(crate)
で宣言することで、クレート外部に不要な依存関係を作らずに済みます。
例えば、ヘルパー関数や内部ロジックの詳細は、pub(crate)
を使って外部から隠蔽しましょう。これにより、クレート外部のユーザーが誤って内部の詳細に依存することを防ぎ、将来的な変更が容易になります。
// src/lib.rs
mod internal {
pub(crate) fn internal_logic() {
println!("This is internal logic, accessible only within the crate.");
}
}
pub fn external_api() {
println!("This is the public API function.");
}
2. クレート内でのテスト用公開を活用する
pub(crate)
は、テストコードの記述にも非常に役立ちます。Rustのテストモジュール内では、pub(crate)
を使用することで、外部には公開したくない実装の詳細をテスト用に利用することができます。これにより、テストコードを充実させつつ、外部からはそのコードにアクセスできないように保護することができます。
例えば、テスト用に特定の関数や構造体にアクセスする必要がある場合、pub(crate)
を使ってクレート内でのみ公開する方法が有効です。
// src/lib.rs
pub(crate) fn add(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add(2, 3), 5);
}
}
テストコード内からはadd
関数にアクセスでき、内部の実装を適切にテストできますが、クレート外部からはアクセスできません。
3. モジュール間の分離とカプセル化
pub(crate)
は、モジュール間でのカプセル化を強化するために使用するのにも役立ちます。モジュールの内部実装を隠蔽しつつ、必要なインターフェースを外部に公開することで、モジュール間での依存関係を整理し、変更の影響範囲を最小限に抑えることができます。
たとえば、あるモジュールでのみ使われるヘルパー関数や中間処理をpub(crate)
で公開することにより、他のモジュールに依存せずにそのモジュールを独立させることができます。これにより、モジュール間の境界を明確にし、コードの理解と保守がしやすくなります。
// src/module.rs
pub(crate) fn internal_helper() {
println!("This helper function is for internal use only.");
}
pub fn public_function() {
println!("This function is for public use.");
internal_helper();
}
上記のコードでは、internal_helper
はクレート内の他のモジュールからはアクセス可能ですが、クレート外部からはアクセスできません。
4. 意図的な隠蔽とセキュリティ
pub(crate)
を使うことで、クレート内部でのみ利用される機能を意図的に隠蔽し、セキュリティを向上させることができます。特に、外部に公開したくない処理や、変更される可能性がある内部ロジックを隠蔽することで、外部クレートからの不正な利用を防ぐことができます。
たとえば、認証や機密情報に関わる処理をpub(crate)
で隠蔽し、外部のクレートやユーザーがそれらにアクセスできないようにすることができます。
// src/lib.rs
pub(crate) fn process_sensitive_data() {
// セキュアなデータ処理を行う内部関数
println!("Processing sensitive data...");
}
pub fn public_function() {
// 外部に公開する安全なAPI
println!("This is the public API.");
}
上記の例では、process_sensitive_data
関数はクレート内でのみアクセス可能で、外部からはアクセスできません。これにより、外部のクレートが内部データを誤って操作するリスクを減らすことができます。
5. APIの設計時におけるモジュールの利用
pub(crate)
は、APIを設計する際にも役立ちます。外部ユーザーには公開したくない実装の詳細を隠蔽し、公開する必要があるものだけをpub
で公開することができます。この方法を採ることで、APIがよりシンプルで一貫性のあるものになります。
公開するべきものと隠蔽するべきものを明確に区別することで、外部からの誤用を防ぎ、APIの利用者に対して誤解を招かないようにすることができます。
// src/lib.rs
mod internal {
pub(crate) fn helper_function() {
println!("This function is for internal use.");
}
}
pub fn public_api() {
println!("This is the public API.");
internal::helper_function(); // 公開API内で内部関数を使用
}
外部の利用者がpublic_api
を呼び出すことで、内部で必要なロジックを処理できますが、内部の詳細にはアクセスできません。
まとめ
pub(crate)
は、Rustでのコード設計において非常に強力なツールであり、適切に使うことでコードの保守性、安全性、テスト容易性を大いに高めることができます。公開範囲を最小化し、クレート内でのモジュール間の分離とカプセル化を行い、意図的にセキュリティを強化することで、クリーンで効率的なコードを維持できます。
`pub(crate)`と他のアクセス修飾子との組み合わせ
Rustでは、アクセス修飾子を組み合わせて使うことで、より細かいアクセス制御が可能です。pub(crate)
を他の修飾子と組み合わせることで、より柔軟なアクセス制御を実現できます。ここでは、pub(crate)
をprivate
やpub
といった他の修飾子と組み合わせる方法を解説します。
1. `pub(crate)`と`private`の組み合わせ
Rustでは、デフォルトでモジュール内のアイテムは「プライベート」(つまり、モジュール外からアクセスできない)です。pub(crate)
とprivate
(デフォルト状態)の組み合わせを使うことで、外部からはアクセスできないが、クレート内でのみ利用可能なアイテムを柔軟に定義できます。
例えば、あるモジュール内で特定の構造体や関数をクレート内でだけ利用したい場合に、pub(crate)
を使ってクレート内に公開し、その他のアイテムはそのままprivate
で隠蔽することができます。
mod mymodule {
// この構造体はクレート内のみで利用
pub(crate) struct InternalStruct {
pub(crate) value: i32,
}
// プライベート関数
fn private_function() {
println!("This is a private function.");
}
// クレート内でのみ公開される
pub(crate) fn use_internal_struct() {
let s = InternalStruct { value: 42 };
println!("InternalStruct value: {}", s.value);
}
}
fn main() {
// `mymodule`内部で公開された関数は使える
mymodule::use_internal_struct();
// `mymodule::InternalStruct`はクレート外からはアクセス不可
// let s = mymodule::InternalStruct { value: 100 }; // コンパイルエラー
}
上記の例では、InternalStruct
とuse_internal_struct
はpub(crate)
で公開され、クレート内からのみ利用可能です。private_function
は完全に隠蔽され、クレート外部からはアクセスできません。
2. `pub(crate)`と`pub`の組み合わせ
pub
とpub(crate)
を組み合わせることで、同じ構造体や関数に異なるアクセスレベルを設定できます。たとえば、構造体のフィールドはクレート内で公開しつつ、その構造体自体は外部に公開する場合などです。
pub struct MyStruct {
pub(crate) internal_field: i32, // クレート内でのみ公開
pub external_field: i32, // クレート外からも公開
}
impl MyStruct {
pub(crate) fn new(internal_field: i32, external_field: i32) -> Self {
MyStruct {
internal_field,
external_field,
}
}
}
fn main() {
// `external_field`は外部からもアクセス可能
let s = MyStruct {
internal_field: 10,
external_field: 20,
};
println!("External field: {}", s.external_field);
// `internal_field`はクレート内のみアクセス可能
// println!("Internal field: {}", s.internal_field); // コンパイルエラー
}
この例では、MyStruct
のinternal_field
はpub(crate)
で公開され、クレート内からのみアクセス可能です。一方で、external_field
はpub
で公開され、外部からもアクセスできます。
3. `pub(crate)`と`unsafe`の組み合わせ
unsafe
はRustで安全性が保証されない操作を行う際に使用される修飾子ですが、pub(crate)
と組み合わせて使用することで、特定のクレート内でのみ安全性を確保する操作を実行することができます。この組み合わせは、特に低レベルな操作やポインタ操作を扱う際に役立ちます。
pub(crate) unsafe fn unsafe_function() {
println!("This is an unsafe function that can be used within the crate.");
}
fn main() {
unsafe {
// クレート内からはアクセスできるが外部からは不可
unsafe_function();
}
// 外部クレートからはアクセス不可
// unsafe { unsafe_function(); } // コンパイルエラー
}
ここでは、unsafe_function
はpub(crate)
で公開されており、クレート内でのみ呼び出すことができます。外部からはアクセスできません。このように、unsafe
とpub(crate)
を組み合わせることで、クレート内での安全性を担保しながらも、特定の機能を制限することが可能です。
4. `pub(crate)`と`#[cfg(test)]`を組み合わせたテスト専用公開
#[cfg(test)]
は、Rustのコンパイル時にテスト用のコードを条件付きでコンパイルするための属性です。これをpub(crate)
と組み合わせることで、テストコード専用に公開するアイテムを制限することができます。テスト用に公開したいが、通常時には非公開にしておきたい関数や構造体に便利です。
pub(crate) fn internal_function() {
println!("This function is for internal use only.");
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_internal_function() {
internal_function(); // テストコード内ではアクセス可能
}
}
fn main() {
// 通常時はアクセスできない
// internal_function(); // コンパイルエラー
}
この場合、internal_function
はpub(crate)
で公開され、クレート内で利用できますが、テストモジュール内ではその関数にアクセスできます。通常のコード実行時にはアクセスできません。
まとめ
pub(crate)
はRustのアクセス制御において非常に強力で柔軟なツールであり、他のアクセス修飾子と組み合わせることで、さらに詳細な公開範囲を指定できます。private
と組み合わせて内部実装を隠蔽したり、pub
と組み合わせてクレート外向けに公開する部分と内部専用の部分を分けたりすることで、安全で効率的なコード設計が可能となります。unsafe
や#[cfg(test)]
との組み合わせによって、より特定のユースケースにも対応できるようになります。
まとめ
本記事では、Rustにおけるpub(crate)
の使い方を中心に、アクセス修飾子の効果的な活用方法について詳しく解説しました。pub(crate)
はクレート内でのみ公開されるアクセス制御を提供し、内部実装の隠蔽やクレート内でのモジュール間の分離を可能にします。適切に使用することで、コードの保守性、セキュリティ、テスト容易性を大きく向上させることができます。
特に、pub(crate)
を他のアクセス修飾子(private
やpub
)やunsafe
、#[cfg(test)]
などと組み合わせることで、柔軟かつ効率的なアクセス制御が実現できます。これにより、外部と内部のインターフェースを適切に分け、クレートの安全性と整合性を保ちながら、実装の詳細を隠蔽することが可能となります。
最終的に、pub(crate)
を使いこなすことで、外部のユーザーに影響を与えることなく、内部での実装変更や最適化を安全に行うことができます。
コメント