Skip to content

Commit 197441e

Browse files
Watson1978claude
andcommitted
ObjectSpace::WeakKeyMap を追加 (Ruby 3.3)
キーへの弱参照を持つマップのクラス。7 つのインスタンスメソッド ([] []= getkey key? delete clear inspect) を収録した。 実機で確認したところ 3.1 / 3.2 では未定義で、3.3 から追加されている。 3.3 / 3.4 / 4.0 でメソッド構成も挙動も同一なので、版の出し分けは front matter の since: "3.3" だけで行い、本文に #%since は使っていない。 ObjectSpace::WeakMap との違い (値への参照が強参照、キーは同一性ではなく 等値性で比較、GC の対象になるオブジェクトだけをキーにできる) を冒頭に 整理した。 []= には、GC の対象にならないオブジェクト (Integer や Symbol など) を キーにすると ArgumentError ("WeakKeyMap keys must be garbage collectable") になることを - **raise** に書いた。ri には記載が無いが、実用上ひっかかる制約。 あわせて ObjectSpace::WeakMap から姉妹クラスへの導線を追加した。WeakMap は 2.0 からあるため、#%since 3.3 で囲まないと 3.0〜3.2 でリンク切れになる。 記載した例はすべて 3.3 / 3.4 / 4.0 で実行して出力が一致することを確認した。 rake check_links はいずれの版も master と同数で、増えていない。 3.0 : 258 -> 258 3.2 : 296 -> 296 3.3 : 295 -> 295 4.0 : 297 -> 297 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent f792e03 commit 197441e

2 files changed

Lines changed: 182 additions & 0 deletions

File tree

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
---
2+
library: _builtin
3+
since: "3.3"
4+
---
5+
# class ObjectSpace::WeakKeyMap < Object
6+
7+
キーへの弱参照を持つ、キーと値の組を保持するクラスです。
8+
9+
キーは他から参照されなくなると GC の対象になり、そのときキーと値の組は
10+
map から取り除かれます。値への参照は強参照なので、map に入っている間は
11+
GC されません。
12+
13+
[c:ObjectSpace::WeakMap] との違いは以下の 3 点です。
14+
15+
- 値への参照が強参照です。map に入っている間は GC されません。
16+
- キーの比較が同一性([m:Object#equal?])ではなく等値性([m:Object#eql?])で
17+
行われます。
18+
- GC の対象になるオブジェクトだけをキーにできます。
19+
20+
```ruby
21+
map = ObjectSpace::WeakKeyMap.new
22+
key = "name"
23+
map[key] = 1
24+
25+
# キーは等値性で比較されるので、別のオブジェクトでも引ける
26+
p map["name"] # => 1
27+
28+
key = nil
29+
GC.start
30+
# キーへの参照が無くなったので、キーと値の組が取り除かれる
31+
p map["name"] # => nil
32+
```
33+
34+
上の例の [m:GC.start] は説明のために書いたもので、いつでもこのとおりに
35+
GC されるとは限りません。
36+
37+
同じ値を表すオブジェクトを 1 つだけ保持しておきたい場合、たとえば
38+
軽量な値オブジェクトのキャッシュを実装する用途に向いています。
39+
[m:ObjectSpace::WeakKeyMap#getkey] を参照してください。
40+
41+
## Instance Methods
42+
43+
### def [](key) -> object | nil
44+
45+
key に対応する値を返します。
46+
47+
key に対応する組が無い場合は nil を返します。
48+
49+
- **param** `key` -- 探すキーを指定します。等値性([m:Object#eql?])で比較されます。
50+
51+
```ruby
52+
map = ObjectSpace::WeakKeyMap.new
53+
key = "name"
54+
map[key] = 1
55+
56+
p map["name"] # => 1
57+
p map["zzz"] # => nil
58+
```
59+
60+
- **SEE** [m:ObjectSpace::WeakKeyMap#\[\]=], [m:ObjectSpace::WeakKeyMap#getkey]
61+
62+
### def []=(key, value)
63+
64+
key に対応する値として value を登録します。
65+
66+
key への参照は弱参照です。他から key を参照するものが無くなると、
67+
キーと値の組は GC によって取り除かれます。値そのものへの参照は強参照です。
68+
69+
key に対応する組が既にある場合は、値だけを置き換えます。
70+
71+
- **param** `key` -- キーを指定します。GC の対象になるオブジェクトだけを
72+
指定できます。
73+
74+
- **param** `value` -- 値を指定します。
75+
76+
- **raise** `ArgumentError` -- GC の対象にならないオブジェクト([c:Integer]
77+
[c:Symbol] など)をキーに指定した場合に発生します。
78+
79+
```ruby
80+
map = ObjectSpace::WeakKeyMap.new
81+
key = "name"
82+
map[key] = 1
83+
p map["name"] # => 1
84+
85+
map[key] = 2
86+
p map["name"] # => 2
87+
88+
map[1] = 3 # ~> ArgumentError
89+
```
90+
91+
- **SEE** [m:ObjectSpace::WeakKeyMap#\[\]]
92+
93+
### def getkey(key) -> object | nil
94+
95+
key と等値なキーが登録されていれば、登録されているほうのオブジェクトを
96+
返します。無い場合は nil を返します。
97+
98+
同じ値を表すオブジェクトを 1 つにまとめる用途に使えます。
99+
100+
- **param** `key` -- 探すキーを指定します。
101+
102+
```ruby
103+
value = { amount: 1, currency: "USD" }
104+
105+
cache = ObjectSpace::WeakKeyMap.new
106+
cache[value] = true
107+
108+
# 等値な別のオブジェクトを渡しても、登録済みのオブジェクトが返る
109+
copy = cache.getkey({ amount: 1, currency: "USD" })
110+
p copy.equal?(value) # => true
111+
```
112+
113+
- **SEE** [m:ObjectSpace::WeakKeyMap#\[\]]
114+
115+
### def key?(key) -> bool
116+
117+
key に対応する組があれば true を、無ければ false を返します。
118+
119+
- **param** `key` -- 探すキーを指定します。
120+
121+
```ruby
122+
map = ObjectSpace::WeakKeyMap.new
123+
key = "name"
124+
map[key] = 1
125+
126+
p map.key?("name") # => true
127+
p map.key?("zzz") # => false
128+
```
129+
130+
### def delete(key) -> object | nil
131+
### def delete(key) {|key| ... } -> object
132+
133+
key に対応する組を取り除き、その値を返します。
134+
135+
key に対応する組が無い場合、ブロックを指定していなければ nil を返します。
136+
ブロックを指定していれば、key を引数としてブロックを実行し、その結果を返します。
137+
key に対応する組がある場合、ブロックは実行されません。
138+
139+
- **param** `key` -- 取り除く組のキーを指定します。
140+
141+
```ruby
142+
map = ObjectSpace::WeakKeyMap.new
143+
key = "name"
144+
map[key] = 1
145+
146+
p map.delete("name") # => 1
147+
p map["name"] # => nil
148+
149+
p map.delete("zzz") # => nil
150+
p map.delete("zzz") { |k| "no #{k}" } # => "no zzz"
151+
```
152+
153+
### def clear -> self
154+
155+
すべての組を取り除きます。`self` を返します。
156+
157+
```ruby
158+
map = ObjectSpace::WeakKeyMap.new
159+
key = "name"
160+
map[key] = 1
161+
162+
map.clear
163+
p map["name"] # => nil
164+
```
165+
166+
### def inspect -> String
167+
168+
`self` の情報を含む文字列を返します。
169+
170+
```ruby
171+
map = ObjectSpace::WeakKeyMap.new
172+
key = "name"
173+
map[key] = 1
174+
175+
p map.inspect # => "#<ObjectSpace::WeakKeyMap:0x00007f8f0a0b1234 size=1>"
176+
```

manual/api/_builtin/ObjectSpace__WeakMap.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ deprecated になった Ruby 4.0 以降では、オブジェクト ID からオ
1515
主に [c:WeakRef] クラスの内部で使用されるため、[lib:weakref] ライブラリ
1616
経由で使用してください。
1717
#%end
18+
#%since 3.3
19+
20+
キーだけを弱参照にし、値は強参照で保持するものとして
21+
[c:ObjectSpace::WeakKeyMap] があります。
22+
このクラスと違い、キーは同一性ではなく等値性で比較されます。
23+
#%end
1824

1925
## Public Instance Methods
2026

0 commit comments

Comments
 (0)