5个版本 (破坏性更新)
0.22.0 | 2024年7月13日 |
---|---|
0.21.0 | 2024年6月29日 |
0.20.0 | 2024年6月10日 |
0.19.0 | 2024年6月10日 |
0.18.0 | 2024年6月9日 |
#2349 in 算法
595 monthly downloads
用于 20 个crate (3 直接)
20KB
126 行
模块 :: clone_dyn_types
派生以复制动态结构。
它是类型,使用 clone_dyn
来避免模板。
默认情况下,由于Rust的 Clone
特性需要编译时了解类型的大小,因此Rust不支持克隆特质对象。通过过程宏,clone_dyn
crate解决了这一限制,允许克隆特质对象集合。建议使用 clone_dyn
而不是此crate,因为 clone_dyn
包含此crate,并提供一个属性宏,只需一行代码即可生成模板。
替代方案
有几个替代方案 dyn-clone,dyn-clonable。与其他选项不同,此解决方案更简洁,使用起来更简单,所有这些都不牺牲结果的质量。
基本用例
演示了如何使用 clone_dyn
使特质对象支持克隆。
由于Rust的 Clone
特性需要编译时了解类型的大小,因此默认情况下,Rust不支持克隆特质对象。通过过程宏,clone_dyn
crate解决了这一限制,允许克隆特质对象集合和crate clone_dyn_types
包含所有类型的实现。
概述
此示例展示了如何使用 clone_dyn
crate 使特质对象(特别是迭代器)支持克隆。它定义了一个自定义特质 IterTrait
,该特质封装了具有特定特性的迭代器,并演示了如何使用 CloneDyn
来克服 Clone
特质的对象安全性约束。
IterTrait 特质
《IterTrait》特质被设计用来表示产生项目引用的迭代器(&'a T
)。这些迭代器还必须实现《ExactSizeIterator》和《DoubleEndedIterator》特质。此外,迭代器必须实现《CloneDyn》特质,这允许复制特质对象。
只要满足指定要求,任何类型都可以实现这个特质。
复制特质对象
Rust 的类型系统由于对象安全性的限制,不允许特质对象直接实现《Clone》特质。具体来说,《Clone》特质需要编译时知道具体类型,而对于特质对象这是不可用的。
clone_dyn_types
包中的《CloneDyn》特质通过允许复制特质对象来解决这个问题。
示例演示了如何为装箱的《IterTrait》特质对象实现《Clone》。
《get_iter》函数
《get_iter》函数返回一个实现了《IterTrait》特质的装箱迭代器。如果输入是 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( feature = "enabled" ) ) ]
fn main() {}
#[ cfg( feature = "enabled" ) ]
fn main()
{
use clone_dyn_types::CloneDyn;
/// Trait that encapsulates an iterator with specific characteristics, tailored for your needs.
pub trait IterTrait< 'a, T >
where
T : 'a,
Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator,
Self : CloneDyn,
{
}
impl< 'a, T, I > IterTrait< 'a, T > for I
where
T : 'a,
Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator,
Self : CloneDyn,
{
}
// Implement `Clone` for boxed `IterTrait` trait objects.
impl< 'c, T > Clone for Box< dyn IterTrait< 'c, T > + 'c >
{
#[ inline ]
fn clone( &self ) -> Self
{
clone_dyn_types::clone_into_box( &**self )
}
}
///
/// 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_types` 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_types::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_types::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_types::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_types::clone_into_box( &**self )
}
}
尝试运行以下命令: cargo run --example clone_dyn_types_trivial
。
查看代码.
将以下内容添加到您的项目中
cargo add clone_dyn_types
从存储库中尝试运行
git clone https://github.com/Wandalen/wTools
cd wTools
cd examples/clone_dyn_types_trivial
cargo run