20个重大版本更新

0.23.0 2024年8月16日
0.22.0 2024年7月13日
0.21.0 2024年6月29日
0.15.0 2024年3月26日
0.1.0 2022年6月26日

#337 in 算法

Download history 646/week @ 2024-05-03 1624/week @ 2024-05-10 737/week @ 2024-05-17 637/week @ 2024-05-24 1476/week @ 2024-05-31 428/week @ 2024-06-07 344/week @ 2024-06-14 164/week @ 2024-06-21 709/week @ 2024-06-28 295/week @ 2024-07-05 520/week @ 2024-07-12 302/week @ 2024-07-19 439/week @ 2024-07-26 156/week @ 2024-08-02 313/week @ 2024-08-09 505/week @ 2024-08-16

1,442 每月下载量
用于 5 个crate (通过 derive_tools)

MIT 许可证

36KB
203

模块 :: clone_dyn

experimental rust-status docs.rs Open in Gitpod discord

派生以克隆dyn结构。

默认情况下,由于Rust的Clone特质需要编译时知道类型的大小,因此不支持克隆trait对象。通过过程宏,clone_dyn crate解决了这个限制,允许克隆trait对象集合。该crate的目的是非常简单的:通过将derive属性应用于特质,以最少的努力和复杂性实现dyn< Trait >的轻松克隆。

替代方案

有几个替代方案dyn-clonedyn-clonable。与其他选项不同,此解决方案更简洁,使用起来要求更少,而不会影响结果的质量。

基本用例

演示了如何使用clone_dyn来启用trait对象的克隆。

默认情况下,由于Rust的Clone特质需要编译时知道类型的大小,因此不支持克隆trait对象。通过过程宏,clone_dyn crate解决了这个限制,允许克隆trait对象集合。

概述

此示例展示了如何使用clone_dyn crate来启用trait对象的克隆,特别是迭代器。它定义了一个自定义特质IterTrait,它封装了一个具有特定特征的迭代器,并演示了如何使用CloneDyn来克服Clone特质的对象安全性限制。

IterTrait特质

《IterTrait》特质被设计用来表示产生引用项的迭代器(&'a T)。这些迭代器还必须实现《ExactSizeIterator》和《DoubleEndedIterator》特质。此外,迭代器必须实现《CloneDyn》特质,它允许克隆特质对象。

此特质适用于满足指定要求的任何类型。

克隆特质对象

由于对象安全性约束,Rust 的类型系统不允许特质对象直接实现《Clone》特质。具体来说,《Clone》特质要求在编译时了解具体的类型,这对于特质对象是不可用的。

来自《clone_dyn》crate 的《CloneDyn》特质通过允许克隆特质对象来解决这个问题,过程宏生成必要的代码以克隆特质对象,从而使克隆特质对象集合成为可能。

以下示例演示了如何为boxed的《IterTrait》特质对象实现《Clone》。

get_iter 函数

get_iter 函数返回一个实现了《IterTrait》特质的boxed迭代器。如果输入是 Some,它返回对向量的迭代器。如果输入是 None,它返回一个空迭代器。

由于代码返回两种不同类型的迭代器,因此无法在这里使用 impl Iterator

  • 当输入是 Some 时,返回 std::slice::Iter
  • 当输入是 None 时,返回 std::iter::Empty

为了处理这种情况,函数返回一个特质对象(Box< dyn IterTrait >)。然而,由于对象安全性约束,Rust 的《Clone》特质不能为特质对象实现。《CloneDyn》特质通过允许克隆特质对象来解决这个问题。

use_iter 函数

use_iter 函数通过克隆迭代器来演示《CloneDyn》特质的使用。然后它遍历克隆的迭代器并打印每个元素。

主函数

主函数通过创建一个向量、获取一个迭代器以及使用迭代器来打印元素来演示整体使用方法。

# #[ cfg( not( all( feature = "enabled", feature = "clone_dyn_meta" ) ) ) ]
# fn main() {}
# #[ cfg( all( feature = "enabled", feature = "clone_dyn_meta" ) ) ]
# fn main()
# {

  use clone_dyn::{ clone_dyn, CloneDyn };

  /// Trait that encapsulates an iterator with specific characteristics, tailored for your needs.
  // Uncomment to see what macro expand into
  // #[ clone_dyn( debug ) ]
  #[ clone_dyn ]
  pub trait IterTrait< 'a, T >
  where
    T : 'a,
    Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator,
    // Self : CloneDyn,
    // There’s no need to explicitly define this bound because the macro will handle it for you.
  {
  }

  impl< 'a, T, I > IterTrait< 'a, T > for I
  where
    T : 'a,
    Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator,
    Self : CloneDyn,
  {
  }

  ///
  /// Function to get an iterator over a vector of integers.
  ///
  /// This function returns a boxed iterator that implements the `IterTrait` trait.
  /// If the input is `Some`, it returns an iterator over the vector.
  /// If the input is `None`, it returns an empty iterator.
  ///
  /// Rust's type system does not allow trait objects to implement the `Clone` trait directly due to object safety constraints.
  /// Specifically, the `Clone` trait requires knowledge of the concrete type at compile time, which is not available for trait objects.
  ///
  /// In this example, we need to return an iterator that can be cloned. Since we are returning a trait object ( `Box< dyn IterTrait >` ),
  /// we cannot directly implement `Clone` for this trait object. This is where the `CloneDyn` trait from the `clone_dyn` crate comes in handy.
  ///
  /// The `CloneDyn` trait provides a workaround for this limitation by allowing trait objects to be cloned.
  /// It uses procedural macros to generate the necessary code for cloning trait objects, making it possible to clone collections of trait objects.
  ///
  /// It's not possible to use `impl Iterator` here because the code returns iterators of two different types:
  /// - `std::slice::Iter` when the input is `Some`.
  /// - `std::iter::Empty` when the input is `None`.
  ///
  /// To handle this, the function returns a trait object (`Box<dyn IterTrait>`).
  /// However, Rust's `Clone` trait cannot be implemented for trait objects due to object safety constraints.
  /// The `CloneDyn` trait addresses this problem by enabling cloning of trait objects.

  pub fn get_iter< 'a >( src : Option< &'a Vec< i32 > > ) -> Box< dyn IterTrait< 'a, &'a i32 > + 'a >
  {
    match &src
    {
      Some( src ) => Box::new( src.iter() ),
      _ => Box::new( core::iter::empty() ),
    }
  }

  /// Function to use an iterator and print its elements.
  ///
  /// This function demonstrates the use of the `CloneDyn` trait by cloning the iterator.
  /// It then iterates over the cloned iterator and prints each element.
  pub fn use_iter< 'a >( iter : Box< dyn IterTrait< 'a, &'a i32 > + 'a > )
  {
    // Clone would not be available if CloneDyn is not implemented for the iterator.
    // And being an object-safe trait, it can't implement Clone.
    // Nevertheless, thanks to CloneDyn, the object is clonable.
    //
    // This line demonstrates cloning the iterator and iterating over the cloned iterator.
    // Without `CloneDyn`, you would need to collect the iterator into a container, allocating memory on the heap.
    iter.clone().for_each( | e | println!( "{e}" ) );

    // Iterate over the original iterator and print each element.
    iter.for_each( | e | println!( "{e}" ) );
  }

  // Create a vector of integers.
  let data = vec![ 1, 2, 3 ];
  // Get an iterator over the vector.
  let iter = get_iter( Some( &data ) );
  // Use the iterator to print its elements.
  use_iter( iter );

# }
如果您使用多线程或异步范式,请为 `Send` 和 `Sync` 也实现特质 `Clone`

#[ allow( non_local_definitions ) ]
impl< 'c, T > Clone for Box< dyn IterTrait< 'c, T > + 'c >
{
  #[ inline ]
  fn clone( &self ) -> Self
  {
    clone_dyn::clone_into_box( &**self )
  }
}

#[ allow( non_local_definitions ) ]
impl< 'c, T > Clone for Box< dyn IterTrait< 'c, T > + Send + 'c >
{
  #[ inline ]
  fn clone( &self ) -> Self
  {
    clone_dyn::clone_into_box( &**self )
  }
}

#[ allow( non_local_definitions ) ]
impl< 'c, T > Clone for Box< dyn IterTrait< 'c, T > + Sync + 'c >
{
  #[ inline ]
  fn clone( &self ) -> Self
  {
    clone_dyn::clone_into_box( &**self )
  }
}

#[ allow( non_local_definitions ) ]
impl< 'c, T > Clone for Box< dyn IterTrait< 'c, T > + Send + Sync + 'c >
{
  #[ inline ]
  fn clone( &self ) -> Self
  {
    clone_dyn::clone_into_box( &**self )
  }
}


尝试运行 cargo run --example clone_dyn_trivial
查看代码.

将它们添加到您的项目中

cargo add clone_dyn

从存储库中尝试

git clone https://github.com/Wandalen/wTools
cd wTools
cd examples/clone_dyn_trivial
cargo run

依赖项

~2MB
~40K SLoC