@@ -2092,6 +2092,88 @@ the preferred way to use traits polymorphically.
2092
2092
2093
2093
This usage of traits is similar to Haskell type classes.
2094
2094
2095
+ ## Trait objects and dynamic method dispatch
2096
+
2097
+ The above allows us to define functions that polymorphically act on
2098
+ values of a single unknown type that conforms to a given trait.
2099
+ However, consider this function:
2100
+
2101
+ ~~~~
2102
+ # type Circle = int; type Rectangle = int;
2103
+ # impl int: Drawable { fn draw() {} }
2104
+ # fn new_circle() -> int { 1 }
2105
+ trait Drawable { fn draw(); }
2106
+
2107
+ fn draw_all<T: Drawable>(shapes: ~[T]) {
2108
+ for shapes.each |shape| { shape.draw(); }
2109
+ }
2110
+ # let c: Circle = new_circle();
2111
+ # draw_all(~[c]);
2112
+ ~~~~
2113
+
2114
+ You can call that on an array of circles, or an array of squares
2115
+ (assuming those have suitable ` Drawable ` traits defined), but not on
2116
+ an array containing both circles and squares. When such behavior is
2117
+ needed, a trait name can alternately be used as a type, called
2118
+ an _ object_ .
2119
+
2120
+ ~~~~
2121
+ # trait Drawable { fn draw(); }
2122
+ fn draw_all(shapes: &[@Drawable]) {
2123
+ for shapes.each |shape| { shape.draw(); }
2124
+ }
2125
+ ~~~~
2126
+
2127
+ In this example, there is no type parameter. Instead, the ` @Drawable `
2128
+ type denotes any managed box value that implements the ` Drawable `
2129
+ trait. To construct such a value, you use the ` as ` operator to cast a
2130
+ value to an object:
2131
+
2132
+ ~~~~
2133
+ # type Circle = int; type Rectangle = bool;
2134
+ # trait Drawable { fn draw(); }
2135
+ # fn new_circle() -> Circle { 1 }
2136
+ # fn new_rectangle() -> Rectangle { true }
2137
+ # fn draw_all(shapes: &[@Drawable]) {}
2138
+
2139
+ impl Circle: Drawable { fn draw() { ... } }
2140
+
2141
+ impl Rectangle: Drawable { fn draw() { ... } }
2142
+
2143
+ let c: @Circle = @new_circle();
2144
+ let r: @Rectangle = @new_rectangle();
2145
+ draw_all([c as @Drawable, r as @Drawable]);
2146
+ ~~~~
2147
+
2148
+ We omit the code for ` new_circle ` and ` new_rectangle ` ; imagine that
2149
+ these just return ` Circle ` s and ` Rectangle ` s with a default size. Note
2150
+ that, like strings and vectors, objects have dynamic size and may
2151
+ only be referred to via one of the pointer types.
2152
+ Other pointer types work as well.
2153
+ Casts to traits may only be done with compatible pointers so,
2154
+ for example, an ` @Circle ` may not be cast to an ` ~Drawable ` .
2155
+
2156
+ ~~~
2157
+ # type Circle = int; type Rectangle = int;
2158
+ # trait Drawable { fn draw(); }
2159
+ # impl int: Drawable { fn draw() {} }
2160
+ # fn new_circle() -> int { 1 }
2161
+ # fn new_rectangle() -> int { 2 }
2162
+ // A managed object
2163
+ let boxy: @Drawable = @new_circle() as @Drawable;
2164
+ // An owned object
2165
+ let owny: ~Drawable = ~new_circle() as ~Drawable;
2166
+ // A borrowed object
2167
+ let stacky: &Drawable = &new_circle() as &Drawable;
2168
+ ~~~
2169
+
2170
+ Method calls to trait types are _ dynamically dispatched_ . Since the
2171
+ compiler doesn't know specifically which functions to call at compile
2172
+ time, it uses a lookup table (also known as a vtable or dictionary) to
2173
+ select the method to call at runtime.
2174
+
2175
+ This usage of traits is similar to Java interfaces.
2176
+
2095
2177
## Static methods
2096
2178
2097
2179
Traits can define _ static_ methods, which don't have an implicit ` self ` argument.
@@ -2179,88 +2261,6 @@ let nonsense = mycircle.radius() * mycircle.area();
2179
2261
2180
2262
> *** Note:*** Trait inheritance does not actually work with objects yet
2181
2263
2182
- ## Trait objects and dynamic method dispatch
2183
-
2184
- The above allows us to define functions that polymorphically act on
2185
- values of a single unknown type that conforms to a given trait.
2186
- However, consider this function:
2187
-
2188
- ~~~~
2189
- # type Circle = int; type Rectangle = int;
2190
- # impl int: Drawable { fn draw() {} }
2191
- # fn new_circle() -> int { 1 }
2192
- trait Drawable { fn draw(); }
2193
-
2194
- fn draw_all<T: Drawable>(shapes: ~[T]) {
2195
- for shapes.each |shape| { shape.draw(); }
2196
- }
2197
- # let c: Circle = new_circle();
2198
- # draw_all(~[c]);
2199
- ~~~~
2200
-
2201
- You can call that on an array of circles, or an array of squares
2202
- (assuming those have suitable ` Drawable ` traits defined), but not on
2203
- an array containing both circles and squares. When such behavior is
2204
- needed, a trait name can alternately be used as a type, called
2205
- an _ object_ .
2206
-
2207
- ~~~~
2208
- # trait Drawable { fn draw(); }
2209
- fn draw_all(shapes: &[@Drawable]) {
2210
- for shapes.each |shape| { shape.draw(); }
2211
- }
2212
- ~~~~
2213
-
2214
- In this example, there is no type parameter. Instead, the ` @Drawable `
2215
- type denotes any managed box value that implements the ` Drawable `
2216
- trait. To construct such a value, you use the ` as ` operator to cast a
2217
- value to an object:
2218
-
2219
- ~~~~
2220
- # type Circle = int; type Rectangle = bool;
2221
- # trait Drawable { fn draw(); }
2222
- # fn new_circle() -> Circle { 1 }
2223
- # fn new_rectangle() -> Rectangle { true }
2224
- # fn draw_all(shapes: &[@Drawable]) {}
2225
-
2226
- impl Circle: Drawable { fn draw() { ... } }
2227
-
2228
- impl Rectangle: Drawable { fn draw() { ... } }
2229
-
2230
- let c: @Circle = @new_circle();
2231
- let r: @Rectangle = @new_rectangle();
2232
- draw_all([c as @Drawable, r as @Drawable]);
2233
- ~~~~
2234
-
2235
- We omit the code for ` new_circle ` and ` new_rectangle ` ; imagine that
2236
- these just return ` Circle ` s and ` Rectangle ` s with a default size. Note
2237
- that, like strings and vectors, objects have dynamic size and may
2238
- only be referred to via one of the pointer types.
2239
- Other pointer types work as well.
2240
- Casts to traits may only be done with compatible pointers so,
2241
- for example, an ` @Circle ` may not be cast to an ` ~Drawable ` .
2242
-
2243
- ~~~
2244
- # type Circle = int; type Rectangle = int;
2245
- # trait Drawable { fn draw(); }
2246
- # impl int: Drawable { fn draw() {} }
2247
- # fn new_circle() -> int { 1 }
2248
- # fn new_rectangle() -> int { 2 }
2249
- // A managed object
2250
- let boxy: @Drawable = @new_circle() as @Drawable;
2251
- // An owned object
2252
- let owny: ~Drawable = ~new_circle() as ~Drawable;
2253
- // A borrowed object
2254
- let stacky: &Drawable = &new_circle() as &Drawable;
2255
- ~~~
2256
-
2257
- Method calls to trait types are _ dynamically dispatched_ . Since the
2258
- compiler doesn't know specifically which functions to call at compile
2259
- time, it uses a lookup table (also known as a vtable or dictionary) to
2260
- select the method to call at runtime.
2261
-
2262
- This usage of traits is similar to Java interfaces.
2263
-
2264
2264
# Modules and crates
2265
2265
2266
2266
The Rust namespace is arranged in a hierarchy of modules. Each source
0 commit comments