使用需要大小的特征对象

nat*_*ore 5 generics traits rust

我想要一个LinkedListtrait 对象包装器结构。内部将是 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()));
}
Run Code Online (Sandbox Code Playgroud)

产生以下错误:

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()));
                                                ^~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

我尝试添加+ Sized到的定义HStream,以及做inner一个Box<T>,都产生了同样的错误。

目前可以用 Rust 做到这一点吗?如果是这样,语法是什么?

DK.*_*DK. 5

好的,这里有一些问题。整理编译器错误列表:

<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`
Run Code Online (Sandbox Code Playgroud)

因为HStream没有编译时可计算的大小,所以它不能代替类型参数T所有类型参数都隐含地要求被替换的类型是编译时大小的。如果您想允许动态大小的类型,您需要通过以下方式明确选择退出此隐式绑定:

<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`
Run Code Online (Sandbox Code Playgroud)

特征不实现自身。您要求一种实现 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`
Run Code Online (Sandbox Code Playgroud)

这是 KO 问题:HStream 不能与动态调度,period 一起使用。它不是对象安全的。这很可能是因为Clone需求。

对上述所有问题的“修复”是重新设计您的类型,以使问题不存在。这意味着什么是不可能知道的,因为这里没有足够的上下文来说明您要做什么。

但是,在盲目刺杀时,这可能是没有泛型的情况(无论如何,您似乎没有使用过):

<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`
Run Code Online (Sandbox Code Playgroud)


Fra*_*gné 5

HStream您不能直接使用该类型;它不代表任何东西。它仅用于构造派生指针类型,例如&HStreamBox<HStream>

最简单的解决方案是使用LinkedListof Stream<Box<HStream>>

fn main() {
    let mut list = Arc::new(Mutex::new(LinkedList::<Stream<Box<HStream>>>::new()));
}
Run Code Online (Sandbox Code Playgroud)

然后,我们只需要实现HStreamfor 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> HStream for Box<HStream + 'a> {}
Run Code Online (Sandbox Code Playgroud)

请注意,这缺少一个特征Clone......

Clone不是对象安全的,这意味着无法为该特征创建特征对象类型,例如&CloneBox<Clone>Clone不是对象安全的,因为它的clone方法返回Self,它代表实现者的具体类型。如果您通过特征对象使用此方法,编译器将无法提前知道结果的类型(它可能是任何 的Clone实现者!)。

由于HStream是 的子特征CloneHStream因此也不是对象安全的。结果是我们Clone根本无法实现,并且类似的类型Box<HStream>不合法使用。

然而,我们可以通过创建我们自己的对象安全特征来解决这个问题。我们甚至可以在实现标准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>
    }
}
Run Code Online (Sandbox Code Playgroud)

Clone将绑定的特征替换HStreamBoxedHStreamClone,就可以开始了!

pub trait HStream: HRecv + HSend + AsRawFd + BoxedHStreamClone {}
Run Code Online (Sandbox Code Playgroud)

这是最终的代码:

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()));
}
Run Code Online (Sandbox Code Playgroud)