【问题标题】:Working with trait objects requiring sized使用需要大小的特征对象
【发布时间】:2016-01-13 04:06:40
【问题描述】:

我想要一个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&lt;T&gt;,都产生相同的错误。

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

【问题讨论】:

    标签: generics rust traits


    【解决方案1】:

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

    <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 没有编译时可计算大小,所以它不能代替类型参数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`
    

    特征不会自行实现。您要求的类型实现 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 不能与动态调度一起使用,句号。这不是对象安全的。这很可能是因为 Clone 要求。

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

    不过,在盲目的尝试中,如果没有泛型(无论如何你似乎没有使用),它可能看起来像这样:

    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()));
    }
    

    【讨论】:

      【解决方案2】:

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

      最简单的解决方案是使用LinkedListStream&lt;Box&lt;HStream&gt;&gt;

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

      然后,我们只需为Box&lt;HStream&gt; 实现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 不是对象安全的,这意味着无法为该 trait 创建 trait 对象类型,例如 &amp;CloneBox&lt;Clone&gt;Clone 不是对象安全的,因为它的clone 方法返回Self,它代表了实现者的具体类型。如果您通过 trait 对象使用此方法,编译器将无法提前知道结果的类型(可能是 Clone 的任何实现者!)。

      由于HStreamClone 的子特征,HStream 也不是对象安全的。结果就是我们根本无法实现Clone,而Box&lt;HStream&gt;这样的类型是不合法的。

      但是,我们可以通过创建自己的对象安全 trait 来解决这个问题。我们甚至可以在实现标准 Clone trait 的类型上自动实现它。

      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 特征替换为BoxedHStreamClone,就可以开始了!

      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()));
      }
      

      【讨论】:

      • 感谢您花时间回答,两个答案得出的结论相同,所以我选择了第一个提交的答案。再次感谢:)
      猜你喜欢
      • 1970-01-01
      • 2019-05-28
      • 2022-12-02
      • 1970-01-01
      • 1970-01-01
      • 2022-08-03
      • 2021-01-24
      • 2010-10-31
      • 1970-01-01
      相关资源
      最近更新 更多