简体   繁体   English

使用需要大小的特征对象

[英]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> . 它仅用于构造派生指针类型,例如&HStreamBox<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不是对象安全的,这意味着无法为该特征创建特征对象类型,例如&CloneBox<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. 由于HStreamClone ,因此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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM