为什么我不能用 let _: Arc<dyn Trait> = value.into() 创建一个特征对象?
Why can't I create a trait object with let _: Arc<dyn Trait> = value.into()?
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
}
结果
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`
为什么 Arc::new(value)
编译但 value.into()
不编译?我不明白为什么 Arc<T>::new()
is satisfied while From<T>::from
不是。
impl<T> Arc<T> {
pub fn new(data: T) -> Arc<T>
}
impl<T> From<T> for Arc<T> {
fn from(t: T) -> Arc<T>
}
对于所有通用 Rust 代码,在任何 T
上都有一个隐式 Sized
绑定。这个:
fn func<T>(t: &T) {}
其实是这样的:
fn func<T: Sized>(t: &T) {}
这可能并不总是您想要的,因此这是您必须明确选择退出的唯一特征,如下所示:
fn func<T: ?Sized>(t: &T) {}
所以在你的情况下:
impl<T> From<T> for Arc<T> {
fn from(t: T) -> Arc<T>
}
实际上是:
impl<T: Sized> From<T> for Arc<T> {
fn from(t: T) -> Arc<T>
}
这就是为什么你不能 some_value.into()
一个 Arc<dyn Anything>
因为所有特征对象都没有大小。
至于为什么会有这个限制首先我们可以通过查看From<T>
的定义来判断:
pub trait From<T> {
fn from(T) -> Self;
}
from(T)
意味着它必须接受一些 T
并将其放入函数的调用堆栈中,这意味着 T
在编译时必须具有已知大小,因此必须成为 Sized
.
更新
所以这也适用于 Arc::new(T)
,因为该函数是在 impl 块中定义的,如下所示:
impl<T> for Arc<T> {
fn new(T) -> Arc<T> {
...
}
}
并且当您调用 Arc::new(TraitImpl);
时,您确实是在使用 Sized
类型调用它,因为 TraitImpl
的大小在编译时已知,但随后 unsized coercion 由 let
变量绑定触发,因为您要求 Rust 将 Arc<TraitImpl>
视为 Arc<dyn Trait>
.
当您调用 value.into()
时不会触发此未定大小的强制转换,因为 From<T>
只接受 Sized
类型。
但是,如果您确定要使用 From<T>
,您可以这样做:
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
}
在这个例子中,你清楚地表明你要从一个大小的类型到另一个大小的类型,即 TraitImpl
到 Arc<TraitImpl>
,然后再触发未大小的强制转换 Arc<TraitImpl>
到Arc<dyn Trait>
.
以下是其他变体:
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
}
你这两条线有根本的区别。第一个:
let _: Arc<dyn Trait> = Arc::new(value);
模式对于 Arc::new()
的分辨率并不重要,因为它的定义如您所述:
impl<T> Arc<T> {
pub fn new(data: T) -> Arc<T>
}
所以类型T
是从value
的类型TraitImpl
推导出来的,并且创建了一个Arc<TraitImpl>
。
然后这个类型隐式 到 Arc<dyn Trait>
并且所有编译都很好。
但是第二行比较诡异:
let _: Arc<dyn Trait> = value.into();
由于 TraitImpl
中没有 into
函数,编译器在范围内搜索任何特征并找到 Into<T>::into()
,定义为:
pub trait Into<T> {
fn into(self) -> T;
}
现在编译器想知道 T
是什么类型。由于是函数的return,所以猜测T
是Arc<dyn Trait>
。现在 Into
唯一有趣的实现是 From
:
impl<X, T> Into<T> for X where
T: From<X>
这里X
是TraitImpl
,T
是Arc<dyn Trait>
。如果您查看 Arc
对 From
的影响,它包含了很多,但 none 是适用的。这是最相似的:
impl<T> From<T> for Arc<T>
然后,编译器显示一些失败的候选者并发出错误。
TL;DR; 是你实际上想要做两个转换:从 TraitImpl
到 Arc<TraitImpl>
然后从 Arc<TraitImpl>
至 Arc<dyn Trait>
。但是你不能在一次强制中同时完成这两项操作,编译器必须以某种方式拼写出中间类型。
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
}
结果
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`
为什么 Arc::new(value)
编译但 value.into()
不编译?我不明白为什么 Arc<T>::new()
is satisfied while From<T>::from
不是。
impl<T> Arc<T> {
pub fn new(data: T) -> Arc<T>
}
impl<T> From<T> for Arc<T> {
fn from(t: T) -> Arc<T>
}
对于所有通用 Rust 代码,在任何 T
上都有一个隐式 Sized
绑定。这个:
fn func<T>(t: &T) {}
其实是这样的:
fn func<T: Sized>(t: &T) {}
这可能并不总是您想要的,因此这是您必须明确选择退出的唯一特征,如下所示:
fn func<T: ?Sized>(t: &T) {}
所以在你的情况下:
impl<T> From<T> for Arc<T> {
fn from(t: T) -> Arc<T>
}
实际上是:
impl<T: Sized> From<T> for Arc<T> {
fn from(t: T) -> Arc<T>
}
这就是为什么你不能 some_value.into()
一个 Arc<dyn Anything>
因为所有特征对象都没有大小。
至于为什么会有这个限制首先我们可以通过查看From<T>
的定义来判断:
pub trait From<T> {
fn from(T) -> Self;
}
from(T)
意味着它必须接受一些 T
并将其放入函数的调用堆栈中,这意味着 T
在编译时必须具有已知大小,因此必须成为 Sized
.
更新
所以这也适用于 Arc::new(T)
,因为该函数是在 impl 块中定义的,如下所示:
impl<T> for Arc<T> {
fn new(T) -> Arc<T> {
...
}
}
并且当您调用 Arc::new(TraitImpl);
时,您确实是在使用 Sized
类型调用它,因为 TraitImpl
的大小在编译时已知,但随后 unsized coercion 由 let
变量绑定触发,因为您要求 Rust 将 Arc<TraitImpl>
视为 Arc<dyn Trait>
.
当您调用 value.into()
时不会触发此未定大小的强制转换,因为 From<T>
只接受 Sized
类型。
但是,如果您确定要使用 From<T>
,您可以这样做:
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
}
在这个例子中,你清楚地表明你要从一个大小的类型到另一个大小的类型,即 TraitImpl
到 Arc<TraitImpl>
,然后再触发未大小的强制转换 Arc<TraitImpl>
到Arc<dyn Trait>
.
以下是其他变体:
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
}
你这两条线有根本的区别。第一个:
let _: Arc<dyn Trait> = Arc::new(value);
模式对于 Arc::new()
的分辨率并不重要,因为它的定义如您所述:
impl<T> Arc<T> {
pub fn new(data: T) -> Arc<T>
}
所以类型T
是从value
的类型TraitImpl
推导出来的,并且创建了一个Arc<TraitImpl>
。
然后这个类型隐式 Arc<dyn Trait>
并且所有编译都很好。
但是第二行比较诡异:
let _: Arc<dyn Trait> = value.into();
由于 TraitImpl
中没有 into
函数,编译器在范围内搜索任何特征并找到 Into<T>::into()
,定义为:
pub trait Into<T> {
fn into(self) -> T;
}
现在编译器想知道 T
是什么类型。由于是函数的return,所以猜测T
是Arc<dyn Trait>
。现在 Into
唯一有趣的实现是 From
:
impl<X, T> Into<T> for X where
T: From<X>
这里X
是TraitImpl
,T
是Arc<dyn Trait>
。如果您查看 Arc
对 From
的影响,它包含了很多,但 none 是适用的。这是最相似的:
impl<T> From<T> for Arc<T>
然后,编译器显示一些失败的候选者并发出错误。
TL;DR; 是你实际上想要做两个转换:从 TraitImpl
到 Arc<TraitImpl>
然后从 Arc<TraitImpl>
至 Arc<dyn Trait>
。但是你不能在一次强制中同时完成这两项操作,编译器必须以某种方式拼写出中间类型。