質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
DI (Dependence Injection)

DI (Dependence Injection)は、「依存性の注入」という概念を指します。オブジェクト間で依存性のあるコードを外部の設定ファイルから注入するソフトウェアパターン設計思想です。

Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

Q&A

解決済

1回答

1797閲覧

【Rust】shakuクレートを使いDIコンテナーを導入したいが、Mutexをつけるとエラーが出るので解決したい

akira_kano1101

総合スコア25

DI (Dependence Injection)

DI (Dependence Injection)は、「依存性の注入」という概念を指します。オブジェクト間で依存性のあるコードを外部の設定ファイルから注入するソフトウェアパターン設計思想です。

Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

0グッド

1クリップ

投稿2022/04/29 06:03

編集2022/04/29 06:10

shakuクレートでMutexが付けられない

こんにちは。Rustでソフトウェア開発をしています。

DIコンテナーを導入して簡単にコンポーネントの依存関係を解決したいと思い、調べているとshakuというクレートを見つけました。

サンプルコードを実行してみると問題なく動きました。
このArcに直接dyn Logger入れると動作するのを確認できたのですが、実用的ではないと感じます。

なぜならArcMutexと併せて使うのが一般的で、オブジェクトを可変にできるようにしないと値が固定され変数として意味を成さないからです。

そこでMutexArcに付与してMutex<dyn Logger>を入れるようにして実行してみました。

該当のコード

rust

1use shaku::{module, Component, HasComponent, Interface}; 2use std::sync::{Arc, Mutex}; 3 4trait Logger: Interface { 5 fn log(&self, content: &str); 6} 7 8trait DateLogger: Interface { 9 fn log_date(&self); 10} 11 12#[derive(Component)] 13#[shaku(interface = Logger)] 14struct LoggerImpl; 15 16impl Logger for LoggerImpl { 17 fn log(&self, content: &str) { 18 println!("{}", content); 19 } 20} 21 22#[derive(Component)] 23#[shaku(interface = DateLogger)] 24struct DateLoggerImpl { 25 #[shaku(inject)] 26 logger: Arc<Mutex<dyn Logger>>, // => コンパイルエラー 27 #[shaku(default)] 28 today: String, 29 #[shaku(default)] 30 year: usize, 31} 32 33impl DateLogger for DateLoggerImpl { 34 fn log_date(&self) { 35 self.logger 36 .log(&format!("Today is {}, {}", self.today, self.year)); 37 } 38} 39 40module! { 41 MyModule { 42 components = [LoggerImpl, DateLoggerImpl], 43 providers = [] 44 } 45} 46 47fn main() { 48 let module = MyModule::builder() 49 .with_component_parameters::<DateLoggerImpl>(DateLoggerImplParameters { 50 today: "Jan 26".to_string(), 51 year: 2020, 52 }) 53 .build(); 54 55 let date_logger: &dyn DateLogger = module.resolve_ref(); 56 date_logger.log_date(); 57}

しかしそうするとエラーが出ます。

このエラーが解決できずに困っています。

試したこと

  • LoggerSizedトレイトをつけてみる
  • Mutex<LoggerImpl>Loggerを実装してみる

しかしエラーが出ます。

もし解決方法をご存知の方がいらっしゃいましたら、恐縮ですが教えて頂けないでしょうか。

どうぞよろしくお願いいたします。

エラーメッセージ抜粋

console

1error[E0277]: the size for values of type `(dyn Logger + 'static)` cannot be known at compilation time 2 --> src/main.rs:22:10 3 | 422 | #[derive(Component)] 5 | ^^^^^^^^^ doesn't have a size known at compile-time 6 | 7 = help: within `Mutex<(dyn Logger + 'static)>`, the trait `Sized` is not implemented for `(dyn Logger + 'static)` 8 = note: required because it appears within the type `Mutex<(dyn Logger + 'static)>` 9 = note: required because of the requirements on the impl of `Interface` for `Mutex<(dyn Logger + 'static)>` 10note: required by a bound in `HasComponent` 11 --> /Users/a.kano/.cargo/registry/src/github.com-1ecc6299db9ec823/shaku-0.6.1/src/component.rs:71:27 12 | 1371 | pub trait HasComponent<I: Interface + ?Sized>: ModuleInterface { 14 | ^^^^^^^^^ required by this bound in `HasComponent` 15 = note: this error originates in the derive macro `Component` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `MyModule: HasComponent<Mutex<(dyn Logger + 'static)>>` is not satisfied --> src/main.rs:40:1 | 40 | / module! { 41 | | MyModule { 42 | | components = [LoggerImpl, DateLoggerImpl], 43 | | providers = [] 44 | | } 45 | | } | |_^ the trait `HasComponent<Mutex<(dyn Logger + 'static)>>` is not implemented for `MyModule` | = help: the following implementations were found: <MyModule as HasComponent<(dyn Logger + 'static)>> <MyModule as HasComponent<<DateLoggerImpl as shaku::Component<MyModule>>::Interface>> note: required because of the requirements on the impl of `shaku::Component<MyModule>` for `DateLoggerImpl` --> src/main.rs:22:10 | 22 | #[derive(Component)] | ^^^^^^^^^ 23 | #[shaku(interface = DateLogger)] 24 | struct DateLoggerImpl { | ^^^^^^^^^^^^^^ = note: this error originates in the macro `module` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `MyModule: HasComponent<Mutex<(dyn Logger + 'static)>>` is not satisfied --> src/main.rs:40:1 | 40 | / module! { 41 | | MyModule { 42 | | components = [LoggerImpl, DateLoggerImpl], 43 | | providers = [] 44 | | } 45 | | } | |_^ the trait `HasComponent<Mutex<(dyn Logger + 'static)>>` is not implemented for `MyModule` | = help: the following implementations were found: <MyModule as HasComponent<(dyn Logger + 'static)>> <MyModule as HasComponent<<DateLoggerImpl as shaku::Component<MyModule>>::Interface>> note: required because of the requirements on the impl of `shaku::Component<MyModule>` for `DateLoggerImpl` --> src/main.rs:22:10 | 22 | #[derive(Component)] | ^^^^^^^^^ 23 | #[shaku(interface = DateLogger)] 24 | struct DateLoggerImpl { | ^^^^^^^^^^^^^^ note: required because it appears within the type `MyModule` --> src/main.rs:41:5 | 41 | MyModule { | ^^^^^^^^ note: required by a bound in `Module` --> /Users/a.kano/.cargo/registry/src/github.com-1ecc6299db9ec823/shaku-0.6.1/src/module/module_traits.rs:36:19 | 36 | pub trait Module: ModuleInterface { | ^^^^^^^^^^^^^^^ required by this bound in `Module` = note: this error originates in the macro `module` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `MyModule: HasComponent<Mutex<(dyn Logger + 'static)>>` is not satisfied --> src/main.rs:40:1 | 40 | / module! { 41 | | MyModule { 42 | | components = [LoggerImpl, DateLoggerImpl], 43 | | providers = [] 44 | | } 45 | | } | |_^ the trait `HasComponent<Mutex<(dyn Logger + 'static)>>` is not implemented for `MyModule` | = help: the following implementations were found: <MyModule as HasComponent<(dyn Logger + 'static)>> <MyModule as HasComponent<<DateLoggerImpl as shaku::Component<MyModule>>::Interface>> note: required because of the requirements on the impl of `shaku::Component<MyModule>` for `DateLoggerImpl` --> src/main.rs:22:10 | 22 | #[derive(Component)] | ^^^^^^^^^ 23 | #[shaku(interface = DateLogger)] 24 | struct DateLoggerImpl { | ^^^^^^^^^^^^^^ note: required because it appears within the type `MyModule` --> src/main.rs:41:5 | 41 | MyModule { | ^^^^^^^^ note: required by a bound in `HasComponent` --> /Users/a.kano/.cargo/registry/src/github.com-1ecc6299db9ec823/shaku-0.6.1/src/component.rs:71:48 | 71 | pub trait HasComponent<I: Interface + ?Sized>: ModuleInterface { | ^^^^^^^^^^^^^^^ required by this bound in `HasComponent` = note: this error originates in the macro `module` (in Nightly builds, run with -Z macro-backtrace for more info) For more information about this error, try `rustc --explain E0277`. error: could not compile `try_shaku_mutex` due to 4 previous errors Cargo-Process exited abnormally with code 101 at Fri Apr 29 14:44:53

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

error[E0277]: the size for values of type (dyn Logger + 'static) cannot be known at compilation time

このエラーが発生する理由は、トレイトオブジェクトdyn Loggerを直接Mutexに格納しようとしているためです。トレイトオブジェクトは「対象のトレイトを実装した任意の型(struct, enumなど)」のことですので、structなどの定義によって必要なメモリーサイズが変わります(フィールドが一つもないstructだったり、フィールドが何十個もあるstructだったり) Rustでは、コンパイル時にサイズが一意に定まらない型(サイズ不定型)には、なんらかのポインター経由でアクセスする必要があります。

  • Arc<dyn Logger>
  • Box<dyn Logger>
  • &dyn Logger、など

(サイズが不定な型には、トレイトオブジェクトの他にも、スライス型[u8]や文字列スライス型strなどがあります。これらも&mut [u8]&strのように、なんらかのポインター経由でアクセスする必要があります)

ですから、以下のようにすれば、上記のコンパイルエラーは解消します。

rust

1 // Boxポインター経由でトレイトオブジェクトにアクセスする 2 logger: Arc<Mutex<Box<dyn Logger>>>,

しかし、これを手元で試したところ、別のエラーが発生しました。

console

1error[E0277]: the trait bound `MyModule: HasComponent<Mutex<Box<(dyn Logger + 'static)>>>` is not satisfied 2 --> src/bin/main1.rs:40:1 3 | 440 | / module! { 541 | | MyModule { 642 | | components = [LoggerImpl, DateLoggerImpl], 743 | | providers = [] 844 | | } 945 | | } 10 | |_^ the trait `HasComponent<Mutex<Box<(dyn Logger + 'static)>>>` is not implemented for `MyModule` 11 | 12 = help: the following other types implement trait `HasComponent<I>`: 13 <MyModule as HasComponent<(dyn Logger + 'static)>> 14 <MyModule as HasComponent<<DateLoggerImpl as shaku::Component<MyModule>>::Interface>> 15note: required because of the requirements on the impl of `shaku::Component<MyModule>` for `DateLoggerImpl`

調べたところ、Shakuでは依存注入のところはArc<dyn トレイト>で指定する仕様になっており、Arc<Mutex<Box<dyn トレイト>>>などには変えられないようです。

https://docs.rs/shaku/*/shaku/guide/index.html#structure-your-application

Use Arc<dyn T> for dependencies.

では、以下をどう対処したらいいかですが、

なぜならArcMutexと併せて使うのが一般的で、オブジェクトを可変にできるようにしないと値が固定され変数として意味を成さないからです。

LoggerImplの側で対応することになりそうです。

変更前

rust

1#[derive(Component)] 2#[shaku(interface = Logger)] 3struct LoggerImpl; 4 5impl Logger for LoggerImpl { 6 fn log(&self, content: &str) { 7 println!("{}", content); 8 } 9}

変更後

rust

1#[derive(Component)] 2#[shaku(interface = Logger)] 3struct LoggerImpl { 4 // Mutexが必要なリソースを追加し、shaku(default ...)で初期化するための式を指定する 5 #[shaku(default = Mutex::default())] 6 resource: Mutex<Vec<String>>, 7} 8 9impl Logger for LoggerImpl { 10 fn log(&self, content: &str) { 11 // Mutexが必要なリソースにアクセスする。(サンプルなので特に意味のないことをしている) 12 self.resource.lock().unwrap().push(content.to_string()); 13 println!("{}", content); 14 } 15}

上記のように修正し、DateLoggerImplloggerを元のArc<dyn Logger>に戻したところ、コンパイルに成功し、実行できました。

console

1$ cargo run 2... 3Today is Jan 26, 2020

投稿2022/04/30 00:12

tatsuya6502

総合スコア2035

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

akira_kano1101

2022/04/30 09:54

なるほど!そのひらめきは想定外です! 別に`Arc`そのものに`Mutex`を噛ませる必要はないのですね。 インスタンスだけ`Arc`にして内部のフィールドを`Mutex`にし、メソッド内でそのフィールドに対し処理するということですね。 そんなこと思いもしませんでした。 非常にためになりました。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問