I have the following code that tries to take a reference to a trait object from a boxed trait:
trait T {}
struct S {}
impl T for S {}
fn main() {
let struct_box: Box<S> = Box::new(S {});
let struct_ref: &S = &struct_box;
let trait_box: Box<T> = Box::new(S {});
let trait_ref: &T = &trait_box;
}
The compiler returns the following error:
error[E0277]: the trait bound `std::boxed::Box<T>: T` is not satisfied
--> src/main.rs:12:25
|
12 | let trait_ref: &T = &trait_box;
| ^^^^^^^^^^ the trait `T` is not implemented for `std::boxed::Box<T>`
|
= note: required for the cast to the object type `T`
How do I properly borrow &T from Box<T>?
Box<T> implements the AsRef<T> trait, which provides the method as_ref(), so you can turn it into a reference that way:
let trait_ref: &T = trait_box.as_ref();
Normally, deref coercions mean that you don't usually need to write this out explicitly. If you pass a value of type Box<T> to a function that takes &T, the compiler will insert the conversion for you. If you want to call one of the methods on T that takes &self, the compiler will insert the conversion for you. However, deref coercion doesn't apply to a cast to a trait object type (the compiler will choose an unsizing coercion instead, which is what happens in your example).
Borrow the contents of the Box, rather than the Box itself:
let trait_ref: &T = &*trait_box;
The reason the line involving &S works is because the only way for Rust to get from Box<S> to &S is via "deref coercion"; that is, it repeatedly dereferences the value until either the types match, or it can't dereference any further.
Coercing to a trait object, on the other hand, isn't done using dereferencing at all; it involves constructing a new pointer directly from the given one. If it can't do that, it fails.
Related
I have an Option<&str> and I would like to end up with an Option<String>. For other types, Option::cloned would be an easy way to do that. The docs even say:
pub fn cloned(self) -> Option<T>
Maps an Option<&T> to an Option<T> by cloning the contents of the option.
However, trying this actually results in a compile error:
fn main() {
let unowned_str_maybe: Option<&str> = Some("abc");
let owned_str_maybe: Option<String> = unowned_str_maybe.cloned(); // <-- unsatisfied trait bounds
println!("{:?}", owned_str_maybe);
}
/* Compile error is:
error[E0599]: the method `cloned` exists for enum `Option<&str>`, but its trait bounds were not satisfied
--> src/main.rs:5:61
|
5 | let owned_str_maybe: Option<String> = unowned_str_maybe.cloned(); // <-- unsatisfied trait bounds
| ^^^^^^ method cannot be called on `Option<&str>` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`str: Sized`
`str: Clone`
`Option<&str>: Iterator`
which is required by `&mut Option<&str>: Iterator`
*/
Using a more verbose (less idiomatic?) construction of .map(|x| x.to_string()) does compile. Why does Option::cloned not work for converting &str to String?
The reason is that Clone (which is used by Option::cloned) is used only to convert from &T to T, not from &T to U, even if semantically U is an owned version of &T (as String is to &str). In fact, you probably wouldn't expect this function to compile:
fn cloned(input: &str) -> String {
input.clone()
}
But Option::cloned is, essentially, .map(cloned), so it will work only if cloned works.
In fact, your approach with to_string is probably idiomatic. You probably could use function reference instead of closure, i.e. .map(ToString::to_string), or replace to_string with to_owned, but this is not so important.
I have the following code that tries to take a reference to a trait object from a boxed trait:
trait T {}
struct S {}
impl T for S {}
fn main() {
let struct_box: Box<S> = Box::new(S {});
let struct_ref: &S = &struct_box;
let trait_box: Box<T> = Box::new(S {});
let trait_ref: &T = &trait_box;
}
The compiler returns the following error:
error[E0277]: the trait bound `std::boxed::Box<T>: T` is not satisfied
--> src/main.rs:12:25
|
12 | let trait_ref: &T = &trait_box;
| ^^^^^^^^^^ the trait `T` is not implemented for `std::boxed::Box<T>`
|
= note: required for the cast to the object type `T`
How do I properly borrow &T from Box<T>?
Box<T> implements the AsRef<T> trait, which provides the method as_ref(), so you can turn it into a reference that way:
let trait_ref: &T = trait_box.as_ref();
Normally, deref coercions mean that you don't usually need to write this out explicitly. If you pass a value of type Box<T> to a function that takes &T, the compiler will insert the conversion for you. If you want to call one of the methods on T that takes &self, the compiler will insert the conversion for you. However, deref coercion doesn't apply to a cast to a trait object type (the compiler will choose an unsizing coercion instead, which is what happens in your example).
Borrow the contents of the Box, rather than the Box itself:
let trait_ref: &T = &*trait_box;
The reason the line involving &S works is because the only way for Rust to get from Box<S> to &S is via "deref coercion"; that is, it repeatedly dereferences the value until either the types match, or it can't dereference any further.
Coercing to a trait object, on the other hand, isn't done using dereferencing at all; it involves constructing a new pointer directly from the given one. If it can't do that, it fails.
In Rust, references as well as Box<T>, Rc<T>, and Arc<T> allow the creation of a trait object (e.g., from Box<Type> to Box<dyn Trait>). But is there a way to allow the same conversion with a user-defined generic "smart pointer" type?
For example, MyBox<T> is a thin wrapper around Box<T> but the code below results in a compilation error:
use std::io::Write;
pub fn main() {
let std_box: Box<Vec<u8>> = Box::new(Vec::new());
let std_dyn: Box<dyn Write> = std_box;
// ^ this conversion is allowed.
let my_box: MyBox<Vec<u8>> = MyBox { t: Box::new(Vec::new()) };
let my_dyn: MyBox<dyn Write> = my_box;
// ^ this conversion is not allowed.
}
struct MyBox<T: ?Sized> {
t: Box<T>,
}
error[E0308]: mismatched types
--> traits/src/trait_objs.rs:7:36
|
7 | let my_dyn: MyBox<dyn Write> = my_box;
| ---------------- ^^^^^^ expected trait object `dyn std::io::Write`, found struct `Vec`
| |
| expected due to this
|
= note: expected struct `MyBox<dyn std::io::Write>`
found struct `MyBox<Vec<u8>>`
Unfortunately, it looks like the answer is "you don't" for Rust Stable. Rust is very conservative in which implicit coercions it allows. In particular, from the docs, we see the rule that's kicking in for Box.
Coercion is allowed between the following types:
...
TyCtor(T) to TyCtor(U), where TyCtor(T) is one of
&T
&mut T
*const T
*mut T
Box<T>
and where U can be obtained from T by unsized coercion.
where the relevant unsized coercion rule is
T to dyn U, when T implements U + Sized, and U is object safe.
There's not much room for special casing there, at least not in the current version of Rust.
However, if you're willing to dip into Nightly-only features, then you get the exciting CoerceUnsized trait, whose intended use case is... smart pointers to things which would coerce like a Box would.
#![feature(unsize, coerce_unsized)]
use std::ops::CoerceUnsized;
use std::marker::Unsize;
impl<T, U> CoerceUnsized<MyBox<U>> for MyBox<T> where T: Unsize<U>, U: ?Sized {}
This tells Rust we can coerce MyBox<T> to MyBox<U> if T is "basically the same" as U, for an appropriate definition of "basically the same". No functions are required on the implementation; the trait impl simply needs to exist.
I have the following code that tries to take a reference to a trait object from a boxed trait:
trait T {}
struct S {}
impl T for S {}
fn main() {
let struct_box: Box<S> = Box::new(S {});
let struct_ref: &S = &struct_box;
let trait_box: Box<T> = Box::new(S {});
let trait_ref: &T = &trait_box;
}
The compiler returns the following error:
error[E0277]: the trait bound `std::boxed::Box<T>: T` is not satisfied
--> src/main.rs:12:25
|
12 | let trait_ref: &T = &trait_box;
| ^^^^^^^^^^ the trait `T` is not implemented for `std::boxed::Box<T>`
|
= note: required for the cast to the object type `T`
How do I properly borrow &T from Box<T>?
Box<T> implements the AsRef<T> trait, which provides the method as_ref(), so you can turn it into a reference that way:
let trait_ref: &T = trait_box.as_ref();
Normally, deref coercions mean that you don't usually need to write this out explicitly. If you pass a value of type Box<T> to a function that takes &T, the compiler will insert the conversion for you. If you want to call one of the methods on T that takes &self, the compiler will insert the conversion for you. However, deref coercion doesn't apply to a cast to a trait object type (the compiler will choose an unsizing coercion instead, which is what happens in your example).
Borrow the contents of the Box, rather than the Box itself:
let trait_ref: &T = &*trait_box;
The reason the line involving &S works is because the only way for Rust to get from Box<S> to &S is via "deref coercion"; that is, it repeatedly dereferences the value until either the types match, or it can't dereference any further.
Coercing to a trait object, on the other hand, isn't done using dereferencing at all; it involves constructing a new pointer directly from the given one. If it can't do that, it fails.
I tried to create vector of closures:
fn main() {
let mut vec = Vec::new();
vec.push(Box::new(|| 10));
vec.push(Box::new(|| 20));
println!("{}", vec[0]());
println!("{}", vec[1]());
}
That yielded the following error report:
error[E0308]: mismatched types
--> src/main.rs:5:23
|
5 | vec.push(Box::new(|| 20));
| ^^^^^ expected closure, found a different closure
|
= note: expected type `[closure#src/main.rs:4:23: 4:28]`
found type `[closure#src/main.rs:5:23: 5:28]`
= note: no two closures, even if identical, have the same type
= help: consider boxing your closure and/or using it as a trait object
I fixed it by specifying the type explicitly:
let mut vec: Vec<Box<Fn() -> i32>> = Vec::new();
What is the inferred type of vec and why is it that way?
Each closure has an auto-generated, unique, anonymous type. As soon as you add the first closure to the vector, that is the type of all items in the vector. However, when you try to add the second closure, it has a different auto-generated, unique, anonymous type, and so you get the error listed.
Closures are essentially structs that are created by the compiler that implement one of the Fn* traits. The struct contains fields for all the variables captured by the closure, so it by definition needs to be unique, as each closure will capture different numbers and types of variables.
Why can't it just infer Box<Fn() -> i32>?
"can't" is a tough question to answer. It's possible that the compiler could iterate through all the traits of every type that is used to see if some intersection caused the code to compile, but that feels a bit magical to me. You could try opening a feature request or discussing it on one of the forums to see if there is general acceptance of such an idea.
However, Rust does try to make things explicit, especially things that might involve performance. When you go from a concrete struct to a trait object, you are introducing indirection, which has the possibility of being slower.
Right now, the Fn* traits work the same as a user-constructed trait:
trait MyTrait {
fn hello(&self) {}
}
struct MyStruct1;
impl MyTrait for MyStruct1 {}
struct MyStruct2;
impl MyTrait for MyStruct2 {}
fn main() {
let mut things = vec![];
things.push(MyStruct1);
things.push(MyStruct2);
}
error[E0308]: mismatched types
--> src/main.rs:14:17
|
14 | things.push(MyStruct2);
| ^^^^^^^^^ expected struct `MyStruct1`, found struct `MyStruct2`
|
= note: expected type `MyStruct1`
found type `MyStruct2`