使用需要大小的特征对象
Working with trait objects requiring sized
我想要一个 LinkedList
特征对象包装器结构。内部将是 Ssl 或非 Ssl 流的流类型。我的希望是传递结构包装器,只要内部符合相同的特征,无论使用何种内部流类型,一切都会正常。
简单示例:
use std::sync::{Arc, Mutex};
use std::collections::LinkedList;
use std::os::unix::io::{RawFd, AsRawFd};
pub trait HRecv {}
pub trait HSend {}
pub trait HStream: HRecv + HSend + AsRawFd + Clone {}
pub struct Stream<T: HStream> {
pub inner: T
}
pub type StreamList = Arc<Mutex<LinkedList<Stream<HStream>>>>;
fn main() {
let mut list = Arc::new(Mutex::new(LinkedList::<Stream<HStream>>::new()));
}
产生以下错误:
error: the trait 'core::marker::Sized' is not implemented for the type 'HStream' [E0277]
let mut list = Arc::new(Mutex::new(LinkedList::<Stream<HStream>>::new()));
^~~~~~~~~~~~~~~
我已经尝试将 + Sized
添加到 HStream
的定义中,以及将 inner
设为 Box<T>
,两者都会产生相同的错误。
目前可以用 Rust 做到这一点吗?如果是这样,语法是什么?
好的,这里有一些问题。查找编译器错误列表:
<anon>:15:53: 15:68 error: the trait `core::marker::Sized` is not implemented for the type `HStream` [E0277]
<anon>:15 let mut list = Arc::new(Mutex::new(LinkedList::<Stream<HStream>>::new()));
^~~~~~~~~~~~~~~
<anon>:15:53: 15:68 help: see the detailed explanation for E0277
<anon>:15:53: 15:68 note: `HStream` does not have a constant size known at compile-time
<anon>:15:53: 15:68 note: required by `Stream`
因为 HStream
没有 compile-time 可计算的大小,它不能代替类型参数 T
。 All 类型参数隐式要求替换类型的大小为 compile-time。如果你想允许动态大小的类型,你需要明确地 opt-out 这个隐式绑定,比如:
<T: ?Sized + HStream>
<anon>:15:53: 15:68 error: the trait `HStream` is not implemented for the type `HStream` [E0277]
<anon>:15 let mut list = Arc::new(Mutex::new(LinkedList::<Stream<HStream>>::new()));
^~~~~~~~~~~~~~~
<anon>:15:53: 15:68 help: see the detailed explanation for E0277
<anon>:15:53: 15:68 note: required by `Stream`
特征没有实现。您要求的类型 实现了 HStream
,但是 HStream
没有实现它自己(它会怎样?)
您必须提供 的类型。
<anon>:15:53: 15:68 error: the trait `HStream` cannot be made into an object [E0038]
<anon>:15 let mut list = Arc::new(Mutex::new(LinkedList::<Stream<HStream>>::new()));
^~~~~~~~~~~~~~~
<anon>:15:53: 15:68 help: see the detailed explanation for E0038
<anon>:15:53: 15:68 note: the trait cannot require that `Self : Sized`
这里是 K-O 问题:HStream
不能 与动态调度一起使用,period。这不是对象安全的。这很可能是因为 Clone
要求。
上述所有内容的 "fix" 是重新设计您的类型,以使问题不存在。这意味着什么是不可能知道的,因为这里没有足够的上下文来说明你正在尝试做什么。
尽管如此,如果不使用泛型(无论如何你似乎都没有使用泛型),它可能看起来像这样:
use std::sync::{Arc, Mutex};
use std::collections::LinkedList;
use std::os::unix::io::{RawFd, AsRawFd};
pub trait HRecv {}
pub trait HSend {}
pub trait HStream: HRecv + HSend + AsRawFd + CloneHStream {}
pub trait CloneHStream { fn clone_h_stream(&self) -> Box<HStream>; }
impl<T> CloneHStream for T where T: 'static + Clone + HStream {
fn clone_h_stream(&self) -> Box<HStream> {
Box::new(self.clone())
}
}
pub struct Stream {
pub inner: Box<HStream>
}
pub type StreamList = Arc<Mutex<LinkedList<Stream>>>;
fn main() {
let mut list = Arc::new(Mutex::new(LinkedList::<Stream>::new()));
}
不能直接使用HStream
类型;它不代表任何东西。它仅用于构造派生指针类型,例如 &HStream
和 Box<HStream>
.
最简单的解决方案是 LinkedList
的 Stream<Box<HStream>>
。
fn main() {
let mut list = Arc::new(Mutex::new(LinkedList::<Stream<Box<HStream>>>::new()));
}
然后,我们只需要为 Box<HStream>
实现 HStream
。
impl<'a> HRecv for Box<HStream + 'a> {}
impl<'a> HSend for Box<HStream + 'a> {}
impl<'a> AsRawFd for Box<HStream + 'a> {
fn as_raw_fd(&self) -> RawFd { (&**self).as_raw_fd() }
}
impl<'a> HStream for Box<HStream + 'a> {}
请注意,这缺少一个特征...Clone
。
Clone
不是 object-safe,这意味着不可能为该特征创建特征对象类型,例如 &Clone
或 Box<Clone>
。 Clone
不是 object-safe 因为它的 clone
方法 returns Self
表示实现者的具体类型。如果您通过特征对象使用此方法,编译器将无法提前知道结果的类型(它可能是 Clone
的任何实现者!)。
因为 HStream
是 Clone
的子特征,所以 HStream
也不是 object-safe。结果是我们根本无法实现 Clone
,像 Box<HStream>
这样的类型是不合法的。
但是,我们可以通过创建自己的 object-safe 特性来解决这个问题。我们甚至可以在实现标准 Clone
特征的类型上自动实现它。
pub trait BoxedHStreamClone {
fn boxed_clone(&self) -> Box<HStream>;
}
// Implementation for all types that implement HStream and Clone and don't hold any borrows
impl<T: HStream + Clone + 'static> BoxedHStreamClone for T {
fn boxed_clone(&self) -> Box<HStream> {
Box::new(self.clone()) as Box<HStream>
}
}
// Implementation for Box<HStream + 'a>, which cannot implement Clone
impl<'a> BoxedHStreamClone for Box<HStream + 'a> {
fn boxed_clone(&self) -> Box<HStream> {
Box::new((&**self).boxed_clone()) as Box<HStream>
}
}
将 HStream
上的 Clone
trait bound 替换为 BoxedHStreamClone
就可以了!
pub trait HStream: HRecv + HSend + AsRawFd + BoxedHStreamClone {}
use std::sync::{Arc, Mutex};
use std::collections::LinkedList;
use std::os::unix::io::{RawFd, AsRawFd};
pub trait BoxedHStreamClone {
fn boxed_clone(&self) -> Box<HStream>;
}
impl<T: HStream + Clone + 'static> BoxedHStreamClone for T {
fn boxed_clone(&self) -> Box<HStream> {
Box::new(self.clone()) as Box<HStream>
}
}
pub trait HRecv {}
pub trait HSend {}
pub trait HStream: HRecv + HSend + AsRawFd + BoxedHStreamClone {}
pub struct Stream<T: HStream> {
pub inner: T
}
pub type StreamList = Arc<Mutex<LinkedList<Stream<Box<HStream>>>>>;
impl<'a> HRecv for Box<HStream + 'a> {}
impl<'a> HSend for Box<HStream + 'a> {}
impl<'a> AsRawFd for Box<HStream + 'a> {
fn as_raw_fd(&self) -> RawFd { (&**self).as_raw_fd() }
}
impl<'a> BoxedHStreamClone for Box<HStream + 'a> {
fn boxed_clone(&self) -> Box<HStream> {
Box::new((&**self).boxed_clone()) as Box<HStream>
}
}
impl<'a> HStream for Box<HStream + 'a> {}
fn main() {
let mut list = Arc::new(Mutex::new(LinkedList::<Stream<Box<HStream>>>::new()));
}
我想要一个 LinkedList
特征对象包装器结构。内部将是 Ssl 或非 Ssl 流的流类型。我的希望是传递结构包装器,只要内部符合相同的特征,无论使用何种内部流类型,一切都会正常。
简单示例:
use std::sync::{Arc, Mutex};
use std::collections::LinkedList;
use std::os::unix::io::{RawFd, AsRawFd};
pub trait HRecv {}
pub trait HSend {}
pub trait HStream: HRecv + HSend + AsRawFd + Clone {}
pub struct Stream<T: HStream> {
pub inner: T
}
pub type StreamList = Arc<Mutex<LinkedList<Stream<HStream>>>>;
fn main() {
let mut list = Arc::new(Mutex::new(LinkedList::<Stream<HStream>>::new()));
}
产生以下错误:
error: the trait 'core::marker::Sized' is not implemented for the type 'HStream' [E0277]
let mut list = Arc::new(Mutex::new(LinkedList::<Stream<HStream>>::new()));
^~~~~~~~~~~~~~~
我已经尝试将 + Sized
添加到 HStream
的定义中,以及将 inner
设为 Box<T>
,两者都会产生相同的错误。
目前可以用 Rust 做到这一点吗?如果是这样,语法是什么?
好的,这里有一些问题。查找编译器错误列表:
<anon>:15:53: 15:68 error: the trait `core::marker::Sized` is not implemented for the type `HStream` [E0277]
<anon>:15 let mut list = Arc::new(Mutex::new(LinkedList::<Stream<HStream>>::new()));
^~~~~~~~~~~~~~~
<anon>:15:53: 15:68 help: see the detailed explanation for E0277
<anon>:15:53: 15:68 note: `HStream` does not have a constant size known at compile-time
<anon>:15:53: 15:68 note: required by `Stream`
因为 HStream
没有 compile-time 可计算的大小,它不能代替类型参数 T
。 All 类型参数隐式要求替换类型的大小为 compile-time。如果你想允许动态大小的类型,你需要明确地 opt-out 这个隐式绑定,比如:
<T: ?Sized + HStream>
<anon>:15:53: 15:68 error: the trait `HStream` is not implemented for the type `HStream` [E0277]
<anon>:15 let mut list = Arc::new(Mutex::new(LinkedList::<Stream<HStream>>::new()));
^~~~~~~~~~~~~~~
<anon>:15:53: 15:68 help: see the detailed explanation for E0277
<anon>:15:53: 15:68 note: required by `Stream`
特征没有实现。您要求的类型 实现了 HStream
,但是 HStream
没有实现它自己(它会怎样?)
您必须提供 的类型。
<anon>:15:53: 15:68 error: the trait `HStream` cannot be made into an object [E0038]
<anon>:15 let mut list = Arc::new(Mutex::new(LinkedList::<Stream<HStream>>::new()));
^~~~~~~~~~~~~~~
<anon>:15:53: 15:68 help: see the detailed explanation for E0038
<anon>:15:53: 15:68 note: the trait cannot require that `Self : Sized`
这里是 K-O 问题:HStream
不能 与动态调度一起使用,period。这不是对象安全的。这很可能是因为 Clone
要求。
上述所有内容的 "fix" 是重新设计您的类型,以使问题不存在。这意味着什么是不可能知道的,因为这里没有足够的上下文来说明你正在尝试做什么。
尽管如此,如果不使用泛型(无论如何你似乎都没有使用泛型),它可能看起来像这样:
use std::sync::{Arc, Mutex};
use std::collections::LinkedList;
use std::os::unix::io::{RawFd, AsRawFd};
pub trait HRecv {}
pub trait HSend {}
pub trait HStream: HRecv + HSend + AsRawFd + CloneHStream {}
pub trait CloneHStream { fn clone_h_stream(&self) -> Box<HStream>; }
impl<T> CloneHStream for T where T: 'static + Clone + HStream {
fn clone_h_stream(&self) -> Box<HStream> {
Box::new(self.clone())
}
}
pub struct Stream {
pub inner: Box<HStream>
}
pub type StreamList = Arc<Mutex<LinkedList<Stream>>>;
fn main() {
let mut list = Arc::new(Mutex::new(LinkedList::<Stream>::new()));
}
不能直接使用HStream
类型;它不代表任何东西。它仅用于构造派生指针类型,例如 &HStream
和 Box<HStream>
.
最简单的解决方案是 LinkedList
的 Stream<Box<HStream>>
。
fn main() {
let mut list = Arc::new(Mutex::new(LinkedList::<Stream<Box<HStream>>>::new()));
}
然后,我们只需要为 Box<HStream>
实现 HStream
。
impl<'a> HRecv for Box<HStream + 'a> {}
impl<'a> HSend for Box<HStream + 'a> {}
impl<'a> AsRawFd for Box<HStream + 'a> {
fn as_raw_fd(&self) -> RawFd { (&**self).as_raw_fd() }
}
impl<'a> HStream for Box<HStream + 'a> {}
请注意,这缺少一个特征...Clone
。
Clone
不是 object-safe,这意味着不可能为该特征创建特征对象类型,例如 &Clone
或 Box<Clone>
。 Clone
不是 object-safe 因为它的 clone
方法 returns Self
表示实现者的具体类型。如果您通过特征对象使用此方法,编译器将无法提前知道结果的类型(它可能是 Clone
的任何实现者!)。
因为 HStream
是 Clone
的子特征,所以 HStream
也不是 object-safe。结果是我们根本无法实现 Clone
,像 Box<HStream>
这样的类型是不合法的。
但是,我们可以通过创建自己的 object-safe 特性来解决这个问题。我们甚至可以在实现标准 Clone
特征的类型上自动实现它。
pub trait BoxedHStreamClone {
fn boxed_clone(&self) -> Box<HStream>;
}
// Implementation for all types that implement HStream and Clone and don't hold any borrows
impl<T: HStream + Clone + 'static> BoxedHStreamClone for T {
fn boxed_clone(&self) -> Box<HStream> {
Box::new(self.clone()) as Box<HStream>
}
}
// Implementation for Box<HStream + 'a>, which cannot implement Clone
impl<'a> BoxedHStreamClone for Box<HStream + 'a> {
fn boxed_clone(&self) -> Box<HStream> {
Box::new((&**self).boxed_clone()) as Box<HStream>
}
}
将 HStream
上的 Clone
trait bound 替换为 BoxedHStreamClone
就可以了!
pub trait HStream: HRecv + HSend + AsRawFd + BoxedHStreamClone {}
use std::sync::{Arc, Mutex};
use std::collections::LinkedList;
use std::os::unix::io::{RawFd, AsRawFd};
pub trait BoxedHStreamClone {
fn boxed_clone(&self) -> Box<HStream>;
}
impl<T: HStream + Clone + 'static> BoxedHStreamClone for T {
fn boxed_clone(&self) -> Box<HStream> {
Box::new(self.clone()) as Box<HStream>
}
}
pub trait HRecv {}
pub trait HSend {}
pub trait HStream: HRecv + HSend + AsRawFd + BoxedHStreamClone {}
pub struct Stream<T: HStream> {
pub inner: T
}
pub type StreamList = Arc<Mutex<LinkedList<Stream<Box<HStream>>>>>;
impl<'a> HRecv for Box<HStream + 'a> {}
impl<'a> HSend for Box<HStream + 'a> {}
impl<'a> AsRawFd for Box<HStream + 'a> {
fn as_raw_fd(&self) -> RawFd { (&**self).as_raw_fd() }
}
impl<'a> BoxedHStreamClone for Box<HStream + 'a> {
fn boxed_clone(&self) -> Box<HStream> {
Box::new((&**self).boxed_clone()) as Box<HStream>
}
}
impl<'a> HStream for Box<HStream + 'a> {}
fn main() {
let mut list = Arc::new(Mutex::new(LinkedList::<Stream<Box<HStream>>>::new()));
}