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

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

新規登録して質問してみよう
ただいま回答率
85.47%
参照

参照は、プログラミングにおいて変数や関数といったメモリ空間上での所在を指示するデータのことを指します。その中にはデータ自体は含まれず、他の場所にある情報を間接的に指示するプログラムです。

キャッシュ

キャッシュはドキュメントやデータを一時的に保管するもので、アクセス処理時間を短くするために使用されます。

Rust

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

Q&A

解決済

1回答

951閲覧

[Rust][thread_local]スマートポインタについて助言がほしい。

hidekiti

総合スコア23

参照

参照は、プログラミングにおいて変数や関数といったメモリ空間上での所在を指示するデータのことを指します。その中にはデータ自体は含まれず、他の場所にある情報を間接的に指示するプログラムです。

キャッシュ

キャッシュはドキュメントやデータを一時的に保管するもので、アクセス処理時間を短くするために使用されます。

Rust

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

0グッド

0クリップ

投稿2021/09/10 14:45

cargo

  • cargo 1.56.0-nightly

以下のようなことを実現したい

  • シングルスレッド
  • Sampleは作るのが大変なオブジェクト
  • Sampleの可変参照をとってメソッドを呼びたい。
  • MAP:CacheMapはthread_localなキャッシュ、ここに一度作ったSampleをキャッシュしておきたい
  • MAPから所有権を取ることはない。sampleメソッドが呼べればいい。

現状書いていてだめなソースコード

rust

1use std::collections::hash::map::HashMap; 2struct Sample { 3 n:usize, 4} 5impl Sample { 6 fn new(n:usize)->Self{ /*Heavy constructer*/ Sample{ n } } 7 fn sample(&mut self){ 8 self.n += 1; 9 } 10} 11struct CacheMap(HashMap<usize,Sample>);/*ココらへんの型がわからない*/ 12impl CacheMap { 13 fn new() -> Self { CacheMap(HashMap::new()) } 14 fn get(&mut self,n:usize) -> Cell<&mut Sample>/*ココらへんの型がわからない*/ { 15 let item = self.0.get_mut(&n); 16 if let Option::Some(s)=item { return Cell::new(s); } 17 let s = Box::new(Sample::new(n)); 18 self.0.insert(n, *s); 19 self.get(n) 20 } 21} 22thread_local!{ 23 static MAP: RefCell<CacheMap>/*ココらへんの型がわからない*/ = RefCell::new(CacheMap::new()); 24} 25fn main() { 26 MAP.with(|m|{ 27 let m = m.borrow_mut(); 28 let c = m.get(4); 29 c.get_mut().sample(); 30 }); 31} 32

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

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

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

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

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

guest

回答1

0

ベストアンサー

stdHashMapですが、以下のメソッドを使うと格納した値の可変参照を取れます。

  • get_mut(キー)
  • entry(キー).or_insert_with(クロージャー)

ですから、CacheMap::get()の戻り値型は&mut SampleとすればOKです。回答のサンプルコードでは可変参照を返すことを強調するためにCacheMap::get_mut()にリネームしました。

entry(キー).or_insert_with(クロージャー)は、キーが存在しないときに値を挿入してくれる便利なメソッドです。(ドキュメント

  • キーがすでに存在するなら&mut 値を返す
  • キーが存在しないならクロージャーを評価することで値を作り、mapに挿入する。そして&mut 値を返す

それを使うと以下のようなコードになります。

rust

1use std::{cell::RefCell, collections::hash_map::HashMap}; 2 3struct Sample { 4 n: usize, 5} 6 7impl Sample { 8 fn new(n: usize) -> Self { 9 // Heavy constructor 10 Sample { n } 11 } 12 13 fn sample(&mut self) { 14 self.n += 1; 15 } 16} 17 18// 引数なしの`new()`を定義するよりも、`Default`を導出する方が便利 19#[derive(Default)] 20struct CacheMap(HashMap<usize, Sample>); 21 22impl CacheMap { 23 // `HashMap`に格納した値の可変参照(`&mut Sample`)が取れるので、戻り値型には 24 // `Cell`などは必要ない。`&mut Sample`をそのまま返せばいい 25 fn get_mut(&mut self, n: usize) -> &mut Sample { 26 // `HashMap::entry(キー).or_insert_with(クロージャー)`は 27 // キーがすでに存在するなら`&mut 値`を返す。 28 // キーが存在しないなら、クロージャーを評価することで値を作り、 29 // それをmapに挿入する。そして`&mut 値`を返す。 30 self.0.entry(n).or_insert_with(|| Sample::new(n)) 31 } 32} 33 34thread_local! { 35 // Defaultを導出したことにより`RefCell::new(CacheMap::new())`と 36 // 書かずに済む。`Default::default()`でOK 37 static MAP: RefCell<CacheMap> = Default::default(); 38} 39 40fn main() { 41 MAP.with(|m| { 42 let mut m = m.borrow_mut(); 43 let c = m.get_mut(4); 44 c.sample(); 45 }); 46}

投稿2021/09/10 16:02

tatsuya6502

総合スコア2035

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

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

hidekiti

2021/09/10 16:56 編集

丁寧にありがとうございます!! そんな便利メソッドがあったり、Defaultが輝いていたりと、ありがたやです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問