Rustでlazy_staticを使ってグローバルでイミュータブルな定数を初期化してみる
以前Rustでチケットモデリングの実装をしたとき、グローバルでイミュータブルな定数を実装できず毎回初期化していたのですが、lazy_staticを使えば解決できるとのことだったので試してみました。 steavevaivai.hatenablog.com
詳しくは以下のQiitaの記事が詳しかったので、それを参考にlazy_staticのクレートを追加して修正を行いました。 qiita.com
具体的な修正部分は以下になるのですが、 github.com
lazy_static! { pub static ref all_plans: Vec<Plan> = { fn make_weekday_notlate_plan( name: PlanName, customer_spec: CustomerSpec, price: i32, ) -> Plan { Plan { name: name, price: price, spec: PlanSpecification { customer_spec: Box::new(customer_spec), business_day_spec_opt: Option::Some(Spec::And( Box::new(Spec::Normal(Box::new(BusinessDaySpec::Weekday))), Box::new(Spec::Not(Box::new(Spec::Normal(Box::new(LateSpec8))))), )), movie_day_spec_opt: Option::None, }, } }; let mut weekday_notlate_plans = vec![ make_weekday_notlate_plan( PlanName::CinemaCitizenSenior, CustomerSpec::CinemaCitizenSenior, 1000, ), make_weekday_notlate_plan( PlanName::CinemaCitizen, CustomerSpec::CinematicCitizen, 1000, ), make_weekday_notlate_plan(PlanName::General, CustomerSpec::General, 1800), make_weekday_notlate_plan(PlanName::Senior, CustomerSpec::Senior, 1100), make_weekday_notlate_plan( PlanName::UniversityStudent, CustomerSpec::UniversityStudent, 1500, ), make_weekday_notlate_plan( PlanName::HighSchoolStudent, CustomerSpec::HighSchoolStudent, 1000, ), ]; fn make_weekday_late_plan(name: PlanName, customer_spec: CustomerSpec, price: i32) -> Plan { Plan { name: name, price: price, spec: PlanSpecification { customer_spec: Box::new(customer_spec), business_day_spec_opt: Option::Some(Spec::And( Box::new(Spec::Normal(Box::new(BusinessDaySpec::Weekday))), Box::new(Spec::Normal(Box::new(LateSpec8))), )), movie_day_spec_opt: Option::None, }, } }; let mut weekday_late_plans = vec![ make_weekday_late_plan( PlanName::CinemaCitizen, CustomerSpec::CinematicCitizen, 1000, ), make_weekday_late_plan( PlanName::CinemaCitizenSenior, CustomerSpec::CinematicCitizen, 1000, ), make_weekday_late_plan(PlanName::Senior, CustomerSpec::Senior, 1100), make_weekday_late_plan(PlanName::General, CustomerSpec::General, 1300), make_weekday_late_plan( PlanName::UniversityStudent, CustomerSpec::UniversityStudent, 1300, ), make_weekday_late_plan( PlanName::HighSchoolStudent, CustomerSpec::HighSchoolStudent, 1000, ), ]; fn make_holiday_notlate_plan( name: PlanName, customer_spec: CustomerSpec, price: i32, ) -> Plan { Plan { name: name, price: price, spec: PlanSpecification { customer_spec: Box::new(customer_spec), business_day_spec_opt: Option::Some(Spec::And( Box::new(Spec::Normal(Box::new(BusinessDaySpec::Holiday))), Box::new(Spec::Not(Box::new(Spec::Normal(Box::new(LateSpec8))))), )), movie_day_spec_opt: Option::None, }, } }; let mut holiday_notlate_plans = vec![ make_holiday_notlate_plan( PlanName::CinemaCitizen, CustomerSpec::CinematicCitizen, 1300, ), make_holiday_notlate_plan( PlanName::CinemaCitizenSenior, CustomerSpec::CinemaCitizenSenior, 1000, ), make_holiday_notlate_plan( PlanName::CinemaCitizenSenior, CustomerSpec::CinemaCitizenSenior, 1100, ), make_holiday_notlate_plan(PlanName::General, CustomerSpec::General, 1800), ]; let mut all = Vec::new(); all.append(&mut weekday_notlate_plans); all.append(&mut weekday_late_plans); all.append(&mut holiday_notlate_plans); fn sort(mut plans: Vec<Plan>) -> Vec<Plan> { plans.sort_by(|a, b| a.price.cmp(&b.price)); plans } sort(all) }; }
これだけだと ~ cannot be shared between threads safely
といったエラーメッセージが表示されます。グローバル(スレッド間)でも安全にデータを扱えるためには、対象のデータに対してSyncを実装しておく必要があるので今回は以下のようにunsafeでSyncをImplしておけばエラーが解消されることが確認できました。
unsafe impl Sync for Plan {}