オブジェクト指向プログラミングにおいて、シングルトンはクラスのインスタンス化を1つのインスタンスに制限し、そのインスタンスへのグローバルなアクセスポイントを提供するデザインパターンです。Rustでは、static
キーワードとunsafe
ブロックを使用してシングルトンを実装することができます。
以下のコードを見てみましょう。
use derive_getters::Getters;
use std::env;
#[derive(Debug, Getters)]
pub struct SingletonInteger {
value: i64,
}
pub fn singleton_integer() -> &'static SingletonInteger {
unsafe {
if SINGLETON_INTEGER.is_none() {
SINGLETON_INTEGER = Some(SingletonInteger { value: 123 });
}
SINGLETON_INTEGER.as_ref().unwrap()
}
}
static mut SINGLETON_INTEGER: Option<SingletonInteger> = None;
このコードは、単一のi64
型のvalue
フィールドを含むSingletonInteger
構造体を宣言しています。Getters
マクロを使用して、value
フィールドに対するgetterを生成します。
singleton_integer()
関数は、静的SingletonInteger
インスタンスへの参照を返します。unsafe
ブロックが使用されているのは、静的可変変数を変更しているためです。 SINGLETON_INTEGER
変数がNone
の場合、新しいSingletonInteger
インスタンスを作成し、value
フィールドを123
に設定します。
なぜvalue
フィールドがプライベートなのか?
Rustでは、フィールドをプライベートにしてアクセサを提供することが推奨されています。これは、フィールドのアクセス方法を制御し、不変条件を強制することができるためです。
この場合、SingletonInteger
インスタンスを1度しかインスタンス化しないようにし、value
フィールドが設定された後に変更されないようにしたいため、value
フィールドをプライベートにしています。
Getters
マクロは、プライベートなvalue
フィールドにgetterを生成するために使用されます。これにより、直接value
フィールドを公開することなく、読み取り専用でvalue
フィールドにアクセスすることができます。
クライアントコードでシングルトンを使用する方法
クライアントコードでsingleton_integer()
関数を使用するには、モジュールをインポートし、関数を呼び出します。
use my_module::singleton_integer;
fn main() {
let value = singleton_integer().value();
println!("The value is {}", value);
}
この例では、singleton_integer()
関数を呼び出してSingletonInteger
インスタンスへの参照を取得し、get_value()
メソッドを呼び出してvalue
フィールドの値を取得しています。
まとめ
この記事では、static
キーワードとunsafe
ブロックを使用してRustでシングルトンを実装する方法を学びました。また、フィールドをプライベートにし、アクセサを提供することが推奨される理由、そしてプライベートフィールドにgetterを生成するためのGetters
マクロを使用する方法についても学びました。
シングルトンを実装することで、クラスのインスタンスを1つだけ作成し、そのインスタンスへのグローバルアクセスを提供することができます。これは、設定やデータベース接続など、アプリケーション全体で1つの状態を維持したい場合などに役立ちます。