mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-01 06:51:58 +00:00
Add E0746 explanation to the index
This commit is contained in:
parent
93293c56e8
commit
4c13d2555c
@ -414,6 +414,7 @@ E0742: include_str!("./error_codes/E0742.md"),
|
||||
E0743: include_str!("./error_codes/E0743.md"),
|
||||
E0744: include_str!("./error_codes/E0744.md"),
|
||||
E0745: include_str!("./error_codes/E0745.md"),
|
||||
E0746: include_str!("./error_codes/E0746.md"),
|
||||
;
|
||||
// E0006, // merged with E0005
|
||||
// E0008, // cannot bind by-move into a pattern guard
|
||||
@ -608,5 +609,4 @@ E0745: include_str!("./error_codes/E0745.md"),
|
||||
E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
|
||||
E0727, // `async` generators are not yet supported
|
||||
E0739, // invalid track_caller application/syntax
|
||||
E0746, // `dyn Trait` return type
|
||||
}
|
||||
|
137
src/librustc_error_codes/error_codes/E0746.md
Normal file
137
src/librustc_error_codes/error_codes/E0746.md
Normal file
@ -0,0 +1,137 @@
|
||||
Return types cannot be `dyn Trait`s as they must be `Sized`.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0746
|
||||
trait T {
|
||||
fn bar(&self);
|
||||
}
|
||||
struct S(usize);
|
||||
impl T for S {
|
||||
fn bar(&self) {}
|
||||
}
|
||||
|
||||
// Having the trait `T` as return type is invalid because bare traits do not
|
||||
have a statically known size:
|
||||
fn foo() -> dyn T {
|
||||
S(42)
|
||||
}
|
||||
```
|
||||
|
||||
To avoid the error there are a couple of options.
|
||||
|
||||
If there is a single type involved, you can use [`impl Trait`]:
|
||||
|
||||
```
|
||||
# trait T {
|
||||
# fn bar(&self);
|
||||
# }
|
||||
# struct S(usize);
|
||||
# impl T for S {
|
||||
# fn bar(&self) {}
|
||||
# }
|
||||
// The compiler will select `S(usize)` as the materialized return type of this
|
||||
// function, but callers will only be able to access associated items from `T`.
|
||||
fn foo() -> impl T {
|
||||
S(42)
|
||||
}
|
||||
```
|
||||
|
||||
If there are multiple types involved, the only way you care to interact with
|
||||
them is through the trait's interface and having to rely on dynamic dispatch is
|
||||
acceptable, then you can use [trait objects] with `Box`, or other container
|
||||
types like `Rc` or `Arc`:
|
||||
|
||||
```
|
||||
# trait T {
|
||||
# fn bar(&self);
|
||||
# }
|
||||
# struct S(usize);
|
||||
# impl T for S {
|
||||
# fn bar(&self) {}
|
||||
# }
|
||||
struct O(&'static str);
|
||||
impl T for O {
|
||||
fn bar(&self) {}
|
||||
}
|
||||
|
||||
// This now returns a "trait object" and callers are only be able to access
|
||||
// associated items from `T`.
|
||||
fn foo(x: bool) -> Box<dyn T> {
|
||||
if x {
|
||||
Box::new(S(42))
|
||||
} else {
|
||||
Box::new(O("val"))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Finally, if you wish to still be able to access the original type, you can
|
||||
create a new `enum` with a variant for each type:
|
||||
|
||||
```
|
||||
# trait T {
|
||||
# fn bar(&self);
|
||||
# }
|
||||
# struct S(usize);
|
||||
# impl T for S {
|
||||
# fn bar(&self) {}
|
||||
# }
|
||||
# struct O(&'static str);
|
||||
# impl T for O {
|
||||
# fn bar(&self) {}
|
||||
# }
|
||||
enum E {
|
||||
S(S),
|
||||
O(O),
|
||||
}
|
||||
|
||||
// The caller can access the original types directly, but it needs to match on
|
||||
// the returned `enum E`.
|
||||
fn foo(x: bool) -> E {
|
||||
if x {
|
||||
E::S(S(42))
|
||||
} else {
|
||||
E::O(O("val"))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can even implement the `trait` on the returned `enum` so the callers
|
||||
*don't* have to match on the returned value to invoke the associated items:
|
||||
|
||||
```
|
||||
# trait T {
|
||||
# fn bar(&self);
|
||||
# }
|
||||
# struct S(usize);
|
||||
# impl T for S {
|
||||
# fn bar(&self) {}
|
||||
# }
|
||||
# struct O(&'static str);
|
||||
# impl T for O {
|
||||
# fn bar(&self) {}
|
||||
# }
|
||||
# enum E {
|
||||
# S(S),
|
||||
# O(O),
|
||||
# }
|
||||
impl T for E {
|
||||
fn bar(&self) {
|
||||
match self {
|
||||
E::S(s) => s.bar(),
|
||||
E::O(o) => o.bar(),
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you decide to use trait objects, be aware that these rely on
|
||||
[dynamic dispatch], which has performance implications, as the compiler needs
|
||||
to emit code that will figure out which method to call *at runtime* instead of
|
||||
during compilation. Using trait objects we are trading flexibility for
|
||||
performance.
|
||||
|
||||
[`impl Trait`]: https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits
|
||||
[trait objects]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types
|
||||
[dynamic dispatch]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html#trait-objects-perform-dynamic-dispatch
|
@ -24,3 +24,4 @@ LL | fn bar() -> impl Trait {
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0746`.
|
||||
|
@ -116,5 +116,5 @@ LL | fn bat() -> impl Trait {
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0308.
|
||||
Some errors have detailed explanations: E0277, E0308, E0746.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
Loading…
Reference in New Issue
Block a user