1
+ <!--
1
2
# Exotically Sized Types
3
+ -->
2
4
5
+ # 奇妙なサイズの型
6
+
7
+ <!--
3
8
Most of the time, we think in terms of types with a fixed, positive size. This
4
9
is not always the case, however.
10
+ -->
5
11
12
+ 私たちは、型は 0 以上の固定サイズを持つと通常考えます。でも常にそうであるとは限りません。
6
13
7
14
8
-
9
-
15
+ <!--
10
16
# Dynamically Sized Types (DSTs)
17
+ -->
18
+
19
+ # 動的サイズの型(DST: Dynamically Sized Type)
11
20
21
+ <!--
12
22
Rust in fact supports Dynamically Sized Types (DSTs): types without a statically
13
23
known size or alignment. On the surface, this is a bit nonsensical: Rust *must*
14
24
know the size and alignment of something in order to correctly work with it! In
@@ -18,38 +28,86 @@ DST consequently becomes a *fat* pointer consisting of the pointer and the
18
28
information that "completes" them (more on this below).
19
29
20
30
There are two major DSTs exposed by the language: trait objects, and slices.
31
+ -->
21
32
33
+ 実際に、Rust は動的にサイズが決まる型(DST)、静的にはサイズやアラインメントがわからない型、
34
+ をサポートしています。
35
+ 一見すると、これは少し馬鹿げているようです。型をうまく扱うためには、
36
+ サイズや型を知らなければ* いけない* ですから。
37
+ こう考えると DST は通常の型ではありません。サイズが静的にわからないので、
38
+ ある種のポインタの裏にしか存在できないのです。
39
+ DST を指すポインタは結果的に、普通のポインタと DST を補完する情報(以下で詳しく説明します)から構成される、
40
+ * 太った* ポインタになります。
41
+
42
+ 言語が提供する DST のうち重要なものが 2 つあります。trait オブジェクトとスライスです。
43
+
44
+ <!--
22
45
A trait object represents some type that implements the traits it specifies.
23
46
The exact original type is *erased* in favor of runtime reflection
24
47
with a vtable containing all the information necessary to use the type.
25
48
This is the information that completes a trait object: a pointer to its vtable.
49
+ -->
50
+
51
+ Trait オブジェクトは、それが指す Trait を実装するある型を表現します。
52
+ 元となった型は消去されますが、vtable とリフレクションとによって実行時にはその型を利用することができます。
53
+ つまり、Trait オブジェクトを補完する情報とは vtable へのポインタとなります。
26
54
55
+ <!--
27
56
A slice is simply a view into some contiguous storage -- typically an array or
28
57
`Vec`. The information that completes a slice is just the number of elements
29
58
it points to.
59
+ -->
30
60
61
+ スライスとは、単純にある連続したスペース(通常はアレイか ` Vec ` )のビューです。
62
+ スライスを補完する情報とは、単にポインタが指すエレメントの数です。
63
+
64
+ <!--
31
65
Structs can actually store a single DST directly as their last field, but this
32
66
makes them a DST as well:
67
+ -->
68
+
69
+ 構造体は、最後のフィールドとして DST を直接含むことができますが、その構造体自体も DST になります。
33
70
71
+ <!--
34
72
```rust
35
73
// Can't be stored on the stack directly
36
74
struct Foo {
37
75
info: u32,
38
76
data: [u8],
39
77
}
40
78
```
79
+ -->
80
+
81
+ ``` rust
82
+ // 直接スタックには置けません。
83
+ struct Foo {
84
+ info : u32 ,
85
+ data : [u8 ],
86
+ }
87
+ ```
41
88
89
+ <!--
42
90
**NOTE: [As of Rust 1.0 struct DSTs are broken if the last field has
43
91
a variable position based on its alignment][dst-issue].**
92
+ -->
44
93
94
+ ** [ Rust 1.0 時点では、最後のフィールドが正しくアラインメントされていない DST 構造体は正しく動きません] [ dst-issue ] **
45
95
46
96
97
+ <!--
98
+ # Zero Sized Types (ZSTs)
99
+ -->
47
100
101
+ # サイズが 0 の型(ZST: Zero Sized Type)
48
102
49
- # Zero Sized Types (ZSTs)
103
+ <!--
50
104
51
105
Rust actually allows types to be specified that occupy no space:
106
+ -->
107
+
108
+ Rust ではなんと、スペースを有しない型を使うことができます。
52
109
110
+ <!--
53
111
```rust
54
112
struct Foo; // No fields = no size
55
113
@@ -60,61 +118,137 @@ struct Baz {
60
118
baz: [u8; 0], // empty array has no size
61
119
}
62
120
```
121
+ -->
63
122
123
+ ``` rust
124
+ struct Foo ; // フィールドがない = サイズ 0
125
+
126
+ // すべてのフィールドのサイズがない = サイズ 0
127
+ struct Baz {
128
+ foo : Foo ,
129
+ qux : (), // empty tuple has no size
130
+ baz : [u8 ; 0 ], // empty array has no size
131
+ }
132
+ ```
133
+
134
+ <!--
64
135
On their own, Zero Sized Types (ZSTs) are, for obvious reasons, pretty useless.
65
136
However as with many curious layout choices in Rust, their potential is realized
66
137
in a generic context: Rust largely understands that any operation that produces
67
138
or stores a ZST can be reduced to a no-op. First off, storing it doesn't even
68
139
make sense -- it doesn't occupy any space. Also there's only one value of that
69
140
type, so anything that loads it can just produce it from the aether -- which is
70
141
also a no-op since it doesn't occupy any space.
142
+ -->
71
143
144
+ サイズ 0 の型(ZST)は、当然ながら、それ自体ではほとんど価値があありません。
145
+ しかし、多くの興味深いレイアウトの選択肢と組み合わせると、ZST が潜在的に役に立つことがいろいろな
146
+ ケースで明らかになります。Rust は、ZST を生成したり保存したりするオペレーションが no-op に
147
+ 還元できることを理解しています。
148
+ そもそも、ZST はスペースを要求しないので、保存することには意味がありません。
149
+ また ZST は 1 つの値しかとらないので、ZST を読み込む操作は、
150
+ 代わりに無から ZST を作り出すことができ、この操作もスペースを必要としないので no-op と同じです。
151
+
152
+ <!--
72
153
One of the most extreme example's of this is Sets and Maps. Given a
73
154
`Map<Key, Value>`, it is common to implement a `Set<Key>` as just a thin wrapper
74
155
around `Map<Key, UselessJunk>`. In many languages, this would necessitate
75
156
allocating space for UselessJunk and doing work to store and load UselessJunk
76
157
only to discard it. Proving this unnecessary would be a difficult analysis for
77
158
the compiler.
159
+ -->
160
+
161
+ 究極の ZST の利用法として、Set と Map を考えてみましょう。
162
+ ` Map<Key, Value> ` があるときに、` Set<Key> ` を ` Map<Key, UselessJunk> ` の
163
+ 簡単なラッパーとして実装することはよくあります。
164
+ 多くの言語では、UselessJunk のスペースを割り当てる必要があるでしょうし、
165
+ 結果的に使わない UselessJunk を保存したり読み込んだりする必要もあるでしょう。
166
+ こういったことが不要であると示すのはコンパイラにとっては難しい仕事でしょう。
78
167
168
+ <!--
79
169
However in Rust, we can just say that `Set<Key> = Map<Key, ()>`. Now Rust
80
170
statically knows that every load and store is useless, and no allocation has any
81
171
size. The result is that the monomorphized code is basically a custom
82
172
implementation of a HashSet with none of the overhead that HashMap would have to
83
173
support values.
174
+ -->
84
175
176
+ しかし Rust では、単に ` Set<Key> = Map<Key, ()> ` と言えばいいだけなのです。
177
+ Rust は静的な解析で、読み込みや保存が無意味であること、メモリ割当が必要ないことを理解します。
178
+ 結果として単態化したコードは、HashSet のためにカスタマイズされ、
179
+ HashMap を使う場合のオーバーヘッドはなくなります。
180
+
181
+ <!--
85
182
Safe code need not worry about ZSTs, but *unsafe* code must be careful about the
86
183
consequence of types with no size. In particular, pointer offsets are no-ops,
87
184
and standard allocators (including jemalloc, the one used by default in Rust)
88
185
may return `nullptr` when a zero-sized allocation is requested, which is
89
186
indistinguishable from out of memory.
187
+ -->
90
188
189
+ 安全なコードは ZST について心配する必要はありませんが、* 危険な* コードは
190
+ サイズ 0 の型を使った時の結果について注意しなくてはなりません。
191
+ 特に、ポインタのオフセットは no-op になることや、
192
+ (Rust のデフォルトである jemalloc を含む)標準的なメモリアロケータは、
193
+ サイズ 0 の割り当て要求には ` nullptr ` を返すこと
194
+ (これはメモリ不足と区別がつきません)に注意してください。
91
195
92
-
93
-
94
-
196
+ <!--
95
197
# Empty Types
198
+ -->
199
+
200
+ # 空の型
96
201
202
+ <!--
97
203
Rust also enables types to be declared that *cannot even be instantiated*. These
98
204
types can only be talked about at the type level, and never at the value level.
99
205
Empty types can be declared by specifying an enum with no variants:
206
+ -->
207
+
208
+ Rust では、* インスタンスを生成できない* 型を宣言することもできます。
209
+ こういう型は、型レベルの話にのみ出てきて、値レベルには出てきません。
210
+ 空の型は、識別子を持たない enum として宣言できます。
100
211
212
+ <!--
101
213
```rust
102
214
enum Void {} // No variants = EMPTY
103
215
```
216
+ -->
217
+
218
+ ``` rust
219
+ enum Void {} // 識別子なし = 空
220
+ ```
104
221
222
+ <!--
105
223
Empty types are even more marginal than ZSTs. The primary motivating example for
106
224
Void types is type-level unreachability. For instance, suppose an API needs to
107
225
return a Result in general, but a specific case actually is infallible. It's
108
226
actually possible to communicate this at the type level by returning a
109
227
`Result<T, Void>`. Consumers of the API can confidently unwrap such a Result
110
228
knowing that it's *statically impossible* for this value to be an `Err`, as
111
229
this would require providing a value of type `Void`.
230
+ -->
112
231
232
+ 空の型は、ZST よりもまれにしか使いません。
233
+ 空の型がもっとも必要になる例としては、型レベルの到達不可能性を示す時です。
234
+ 例えば、ある API は、一般に Result を返す必要がありますが、
235
+ 特定のケースでは絶対に失敗しないことがわかっているとします。
236
+ ` Result<T, Void> ` を返すことで、この事実を型レベルで伝えることが可能です。
237
+ Void 型の値を提供することはできないので、この Result は Err に* なり得ないと静的にわかります* 。
238
+ そのため、この API の利用者は、自信を持って Result を unwrap することができます。
239
+
240
+ <!--
113
241
In principle, Rust can do some interesting analyses and optimizations based
114
242
on this fact. For instance, `Result<T, Void>` could be represented as just `T`,
115
243
because the `Err` case doesn't actually exist. The following *could* also
116
244
compile:
245
+ -->
246
+
247
+ 原理的に、Rust ではこの事実をもとに、興味深い解析と最適化が可能です。
248
+ たとえば、` Result<T, Void> ` は ` Err ` にはなり得ないので、
249
+ ` T ` と表現することができます。以下のコードがコンパイルに通るようにも* できる* でしょう。
117
250
251
+ <!--
118
252
```rust,ignore
119
253
enum Void {}
120
254
@@ -123,15 +257,37 @@ let res: Result<u32, Void> = Ok(0);
123
257
// Err doesn't exist anymore, so Ok is actually irrefutable.
124
258
let Ok(num) = res;
125
259
```
260
+ -->
261
+
262
+ ``` rust,ignore
263
+ enum Void {}
264
+
265
+ let res: Result<u32, Void> = Ok(0);
266
+
267
+ // Err は存在しないので、Ok になることに疑問の余地はありません。
268
+ let Ok(num) = res;
269
+ ```
126
270
271
+ <!--
127
272
But neither of these tricks work today, so all Void types get you is
128
273
the ability to be confident that certain situations are statically impossible.
274
+ -->
275
+
276
+ ただし、どちらの例も現時点では動きません。
277
+ つまり、Void 型による利点は、静的な解析によて、特定の状況が起こらないと確実に言えることだけです。
129
278
279
+ <!--
130
280
One final subtle detail about empty types is that raw pointers to them are
131
281
actually valid to construct, but dereferencing them is Undefined Behavior
132
282
because that doesn't actually make sense. That is, you could model C's `void *`
133
283
type with `*const Void`, but this doesn't necessarily gain anything over using
134
284
e.g. `*const ()`, which *is* safe to randomly dereference.
285
+ -->
286
+
287
+ 最後に細かいことを一つ。空の型を指す生のポインタを構成することは有効ですが、
288
+ それをデリファレンスすることは、意味がないので、未定義の挙動となります。
289
+ つまり、C における ` void * ` と同じような意味で ` *const Void ` を使うこと出来ますが、
290
+ これは、* 安全に* デリファレンスできる型(例えば ` *const () ` )と比べて何も利点はありません。
135
291
136
292
137
293
[ dst-issue ] : https://github.com/rust-lang/rust/issues/26403
0 commit comments