[英]Working with trait objects requiring sized
I'd like to have a LinkedList
of trait object wrapper structs. 我想要一个LinkedList
对象包装器结构的LinkedList
。 The inner would be a stream type for either an Ssl or Non-Ssl stream. 内部将是Ssl或非Ssl流的流类型。 My hope was to pass the struct wrapper around, and as long as the inner conformed to the same trait, everything would be OK regardless of inner stream type being used. 我希望传递struct wrapper,只要内部符合相同的特性,无论使用哪种内部流类型,一切都会好的。
Simple example: 简单的例子:
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()));
}
Produces the following error: 产生以下错误:
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()));
^~~~~~~~~~~~~~~
I've tried adding + Sized
to the definition of HStream
, as well as making inner
a Box<T>
, both produce the same error. 我已经尝试将+ Sized
添加到HStream
的定义中,以及使inner
成为Box<T>
,两者都产生相同的错误。
Is it currently possible to do this with Rust? 目前可以用Rust做到这一点吗? If so, what would the syntax be? 如果是这样,语法是什么?
Ok, there are a few problems here. 好的,这里有一些问题。 Working down the list of compiler errors: 处理编译器错误列表:
<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`
Because HStream
does not have a compile-time computable size, it cannot be substituted for the type parameter T
. 因为HStream
没有编译时可计算的大小,所以它不能替换类型参数T
All type parameters implicitly require the substituted type to be compile-time sized. 所有类型参数都隐式地要求替换类型为编译时大小。 If you want to allow dynamically sized types, you need to explicitly opt-out of this implicit bound by saying something like: 如果要允许动态大小的类型,则需要通过以下方式明确地选择退出此隐式绑定:
<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`
A trait doesn't implement itself. 特质不会自我实现。 You're asking for a type which implements HStream
, but HStream
doesn't implement itself (how would it?) 你问的是一个实现 HStream
的类型,但是HStream
没有自己实现(怎么会这样?)
You have to provide a type which does . 你必须提供一个类型的一样 。
<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`
And here's the KO problem: HStream
cannot be used with dynamic dispatch, period . 这是KO问题: HStream
不能用于动态调度, 周期 。 It's not object safe. 这不是对象安全的。 This is most likely because of the Clone
requirement. 这很可能是因为Clone
要求。
The "fix" to all of the above is to redesign your types so that the problem doesn't exist. 对以上所有内容的“修复”是重新设计您的类型,以便不存在问题。 What that entails is impossible to know because there isn't enough context here to tell what you're trying to do. 所需要的是不可能知道的,因为这里没有足够的背景来说明你想要做什么。
At a blind stab, though, here's what it might look like without generics (which you don't appear to be using, anyway): 然而,在盲目的刺中,这是没有泛型的东西(无论如何你似乎没有使用):
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()));
}
You cannot use the HStream
type directly; 您不能直接使用HStream
类型; it doesn't represent anything. 它并不代表任何东西。 It's only used to construct derived pointer types, such as &HStream
and Box<HStream>
. 它仅用于构造派生指针类型,例如&HStream
和Box<HStream>
。
The simplest solution would be to have a LinkedList
of Stream<Box<HStream>>
. 最简单的解决方案是拥有Stream<Box<HStream>>
的LinkedList
。
fn main() {
let mut list = Arc::new(Mutex::new(LinkedList::<Stream<Box<HStream>>>::new()));
}
Then, we just have to implement HStream
for Box<HStream>
. 然后,我们只需要为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> {}
Note that this is missing a trait... Clone
. 请注意,这是缺少特质... Clone
。
Clone
is not object-safe, which means that it's not possible to create trait object types for that trait, such as &Clone
or Box<Clone>
. Clone
不是对象安全的,这意味着无法为该特征创建特征对象类型,例如&Clone
或Box<Clone>
。 Clone
is not object-safe because its clone
method returns Self
, which represents the concrete type of the implementor. Clone
不是对象安全的,因为它的clone
方法返回Self
,它表示实现者的具体类型。 If you used this method through a trait object, the compiler wouldn't be able to know in advance the type of the result (it could be any of Clone
's implementors!). 如果您通过trait对象使用此方法,编译器将无法事先知道结果的类型(它可能是Clone
的任何实现者!)。
Since HStream
is a subtrait of Clone
, HStream
is not object-safe either. 由于HStream
是Clone
,因此HStream
是对象安全的。 The consequence is that we can't implement Clone
at all, and types like Box<HStream>
are not legal to use. 结果是我们根本无法实现Clone
,而像Box<HStream>
这样的类型不合法使用。
However, we can work around this by making our own, object-safe trait. 但是,我们可以通过制作我们自己的,对象安全的特性来解决这个问题。 We can even automatically implement it on types that implement the standard Clone
trait. 我们甚至可以在实现标准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>
}
}
Replace the Clone
trait bound on HStream
with BoxedHStreamClone
and you're good to go! 用HStream
替换BoxedHStreamClone
上绑定的Clone
特征,你很高兴!
pub trait HStream: HRecv + HSend + AsRawFd + BoxedHStreamClone {}
Here's the final code: 这是最终的代码:
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()));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.