问题
use std::sync::Arc;
trait Trait {}
struct TraitImpl {}
impl Trait for TraitImpl {}
fn main() {
let value = TraitImpl {};
let _: Arc<dyn Trait> = Arc::new(value); // compiles
let _: Arc<dyn Trait> = value.into(); // doesn't compile
}
Result:
error[E0277]: the trait bound `std::sync::Arc<dyn Trait>: std::convert::From<TraitImpl>` is not satisfied
--> src/main.rs:10:35
|
10 | let _: Arc<dyn Trait> = value.into(); // doesn't compile
| ^^^^ the trait `std::convert::From<TraitImpl>` is not implemented for `std::sync::Arc<dyn Trait>`
|
= help: the following implementations were found:
<std::sync::Arc<T> as std::convert::From<T>>
<std::sync::Arc<T> as std::convert::From<std::boxed::Box<T>>>
<std::sync::Arc<[T]> as std::convert::From<&[T]>>
<std::sync::Arc<[T]> as std::convert::From<std::vec::Vec<T>>>
and 8 others
= note: required because of the requirements on the impl of `std::convert::Into<std::sync::Arc<dyn Trait>>` for `TraitImpl`
(Playground)
Why does Arc::new(value) compile but not value.into()? I don't understand why Arc<T>::new() is satisfied while From<T>::from isn't.
impl<T> Arc<T> {
pub fn new(data: T) -> Arc<T>
}
impl<T> From<T> for Arc<T> {
fn from(t: T) -> Arc<T>
}
回答1:
There is a fundamental difference in your two lines. The first one:
let _: Arc<dyn Trait> = Arc::new(value);
The pattern is not important for the resolution of Arc::new(), since it is defined as you noted:
impl<T> Arc<T> {
pub fn new(data: T) -> Arc<T>
}
So the type T is deduced from the type of value that is TraitImpl, and an Arc<TraitImpl> is created.
Then this type is implicitly unsized-coerced to that Arc<dyn Trait> and all compiles fine.
But the second line is tricker:
let _: Arc<dyn Trait> = value.into();
Since there is not an into function in TraitImpl the compiler searches any trait in scope and finds Into<T>::into(), that is defined as:
pub trait Into<T> {
fn into(self) -> T;
}
Now the compiler wonders what type would that T be. Since it is the return of the function, it guesses that T is Arc<dyn Trait>. Now the only interesting implementation of Into is in terms of From:
impl<X, T> Into<T> for X where
T: From<X>
Here X is TraitImpl and T is Arc<dyn Trait>. If you look at the impls of Arc for From, it includes a lot of them, but none that applies. This is the most similar:
impl<T> From<T> for Arc<T>
Then, the compiler shows a few of the failing candidates and emits an error.
The TL;DR; is that you actually want to do two conversions: from TraitImpl to Arc<TraitImpl> and then from Arc<TraitImpl> to Arc<dyn Trait>. But you cannot do both in a single coertion, the compiler must have the intermediate type spelled out somehow.
回答2:
For all generic Rust code there is an implicit Sized bound on any T. This:
fn func<T>(t: &T) {}
Is actually this:
fn func<T: Sized>(t: &T) {}
Which may not always be what you want so it's the only trait you have to explicitly opt-out of like so:
fn func<T: ?Sized>(t: &T) {}
So in your case:
impl<T> From<T> for Arc<T> {
fn from(t: T) -> Arc<T>
}
Is actually:
impl<T: Sized> From<T> for Arc<T> {
fn from(t: T) -> Arc<T>
}
Which is why you can't some_value.into() an Arc<dyn Anything> since all trait objects are unsized.
As to why this restriction exists in the first place we can determine that by looking at the definition of From<T>:
pub trait From<T> {
fn from(T) -> Self;
}
from(T) means it has to take some T and put it in the function's call stack, which means T has to have a known size at compile-time and must therefore be Sized.
Update
So this also applies to Arc::new(T) since that function is defined in an impl block like so:
impl<T> for Arc<T> {
fn new(T) -> Arc<T> {
...
}
}
And when you call Arc::new(TraitImpl); you are indeed calling it with a Sized type since TraitImpl's size is known at compile-time but then an unsized coercion is triggered by the let variable binding since you ask Rust to treat Arc<TraitImpl> as if it was an Arc<dyn Trait>.
This unsized coercion isn't triggered when you call value.into() since From<T> only takes Sized types.
However, if you are determined to use From<T> you can do so like this:
use std::sync::Arc;
trait Trait {}
struct TraitImpl {}
impl Trait for TraitImpl {}
fn main() {
let value = TraitImpl {};
let _: Arc<dyn Trait> = Arc::new(value); // compiles
let value = TraitImpl {};
let _: Arc<dyn Trait> = <Arc<TraitImpl>>::from(value); // also compiles
}
In this example you make it clear you're going from a sized type to another sized type, i.e. TraitImpl to Arc<TraitImpl>, before you trigger the unsized coercion Arc<TraitImpl> to Arc<dyn Trait>.
Here are other variations:
use std::sync::Arc;
trait Trait {}
struct TraitImpl {}
impl Trait for TraitImpl {}
fn main() {
let value = TraitImpl {};
let _: Arc<dyn Trait> = Arc::new(value); // compiles
let value = TraitImpl {};
let _: Arc<dyn Trait> = <Arc<TraitImpl>>::from(value); // compiles
let value = TraitImpl {};
let _: Arc<dyn Trait> = Arc::from(value); // compiles, can infer Arc<TraitImpl> here
let value = TraitImpl {};
let _: Arc<dyn Trait> = Into::<Arc<TraitImpl>>::into(value); // compiles
let value = TraitImpl {};
let _: Arc<dyn Trait> = Into::<Arc<_>>::into(value); // compiles, can infer Arc<TraitImpl> here
let value = TraitImpl {};
let _: Arc<dyn Trait> = Into::into(value); // doesn't compile, infers Arc<dyn Trait> here
}
来源:https://stackoverflow.com/questions/61799081/why-cant-i-create-a-trait-object-with-let-arcdyn-trait-value-into