You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Describe default types for generic parameters, as currently implemented.
There are some differences from RFC 213, but I couldn't find any real
specification, so relied on observed behavior.
fixes#24
Generic type parameters may have default types, using the [DefaultType] syntax. Only type parameters on nominal types and traits may have default types.
267
+
268
+
Defaulted type parameters behave differently in expression and type contexts.
269
+
270
+
r[items.generic.defaulttypes.typectx]
271
+
In type contexts, all non-defaulted type arguments are required, but may be specified as the inferred type `_`. Omitted defaulted type arguments will use the provided default.
272
+
273
+
```rust
274
+
#[derive(Default)]
275
+
structS1<T=u8>(T);
276
+
#[derive(Default)]
277
+
structS2<T, U=u8>(T, U);
278
+
// T defaults to u8: QualifiedTypeInPath is type context
279
+
letx= <S1>::default();
280
+
// T defaults to u8: let Type is type context
281
+
lety:S1=S1::default();
282
+
// U defaults to u8: T is inferred from z2
283
+
letz1:S2<_> =S2::default();
284
+
letz2:S2<u8, _> =z1;
285
+
```
286
+
287
+
r[items.generic.defaulttypes.exprctx]
288
+
In expression contexts, all omitted type arguments are treated as the inferred type `_`. [RFC 213] states that the provided default type will be used as a fallback during inference, but this seems work inconsistently in practice.
289
+
290
+
```rust
291
+
#[derive(Debug, Default)]
292
+
structS<T=u8>(T);
293
+
traitTr { fnfoo(&self); }
294
+
implTrforS<u8> {
295
+
fnfoo(&self) {
296
+
println!("in u8: {:?}", self);
297
+
}
298
+
}
299
+
implTrforS<i32> {
300
+
fnfoo(&self) {
301
+
println!("in i32: {:?}", self);
302
+
}
303
+
}
304
+
// unexpectedly i32, due to interaction with integer fallback
305
+
letx=S(1);
306
+
x.foo();
307
+
// u8, due to type annotation on let
308
+
lety:S=S(2);
309
+
y.foo();
310
+
// unexpectedly i32, due to interaction with integer fallback
311
+
S(3).foo();
312
+
313
+
// errors due to inference failure
314
+
// S::default().foo();
315
+
```
316
+
317
+
r[items.generic.defaulttypes.add]
318
+
Default type parameters are useful on traits. For example, this is the `Add` trait in the standard library that allows customization of the `+` operator.
319
+
320
+
```rust
321
+
traitAdd<Rhs=Self> {
322
+
typeOutput;
323
+
324
+
fnadd(self, rhs:Rhs) ->Self::Output;
325
+
}
326
+
```
327
+
328
+
Many users will not need the added flexibility of specifying a different `Rhs` type for `Add`, but it can be useful. For example, `S1` and `S2` wrap `i32` into distinct types. A custom `Add` implementation allows us to add `S1` to `S2` with some extra behavior.
329
+
330
+
```rust
331
+
# usestd::ops::Add;
332
+
#[derive(Debug)]
333
+
structS1(i32);
334
+
#[derive(Debug)]
335
+
structS2(i32);
336
+
implAddforS1 {
337
+
typeOutput=S1;
338
+
fnadd(self, rhs:S1) ->S1 {
339
+
println!("in S1+S1");
340
+
let (S1(x), S1(y)) = (self, rhs);
341
+
S1(x+y)
342
+
}
343
+
}
344
+
implAdd<S2> forS1 {
345
+
typeOutput=S1;
346
+
fnadd(self, rhs:S2) ->S1 {
347
+
println!("in S1+S2");
348
+
let (S1(x), S2(y)) = (self, rhs);
349
+
S1(x+10*y)
350
+
}
351
+
}
352
+
println!("{:?}", S1(1) +S1(2));
353
+
println!("{:?}", S1(1) +S2(2));
354
+
```
355
+
356
+
r[items.generics.defaulttypes.forbidden]
357
+
Default types are not allowed on implementations or functions.
358
+
359
+
```rust,compile_fail
360
+
struct S;
361
+
trait Tr<T> { fn f(self) -> T; }
362
+
impl<T:Default=u8> Tr<T> for S { fn f(self) -> T { T::default() } }
0 commit comments