2 个版本
0.1.1 | 2023 年 2 月 16 日 |
---|---|
0.1.0 | 2023 年 2 月 16 日 |
2592 in Rust 模式
15KB
150 行
Rust 懒加载函数链库
核心数据类型和特质模仿 Rust 的 迭代器 特质及其 map 方法。但与操作集合不同,本库中的特性和数据类型旨在处理单个值。与 Rust 中的迭代器一样,链式调用默认是 懒加载 的。
❗ Chained 目前处于实验阶段。未来的更新可能会带来破坏性变化 |
---|
本库受 pipe-trait 和 pipeline 库的启发。如果您不需要懒加载,只想简单地进行函数调用或方法调用链,上述库可能更适合您。
使用示例
use chained::*;
use std::{env, fmt::Display};
fn main() {
let count_chars = |s: String| s.chars().count();
fn print_count(count: impl Display) {
println!("Args have a total of {count} chars");
}
// Chaining function calls with regular method syntax
env::args()
.collect::<String>()
.into_chained(count_chars) // Owns value, chains the given Fn/Closure and returns a Chain type
.chain(print_count) // Now you can call chain to add more Fns/Closures
.eval(); // Everything is evaluated only after eval() is called
// Writing the same code more concisely using the macro
// Note: `>>` in the beginning tells the macro to call eval() at the end of the chain
chained!(>> env::args().collect::<String>()
=> count_chars
=> print_count
);
// You can also use commas as separators in the macro
// This produces the same code as above
chained!(>> env::args().collect::<String>(), count_chars, print_count);
// Making use of lazy evaluation
// Note: Since '>>' is not specified in the macro, eval() is not automatically called on this chain
let lazy = chained!(env::args().collect::<String>(), count_chars);
let still_lazy = squared_sqrt(lazy); // Take a look at the fn defined below
// All chained functions are evaluated only after eval() is called
still_lazy.chain(|x| println!("{x}")).eval();
}
// Use impl Chained just like you'd use impl Iterator
fn squared_sqrt(x: impl Chained<Item = usize>) -> impl Chained<Item = f32> {
let squared = |x: usize| x.pow(2);
let sqrt = |x| (x as f32).sqrt();
x.chain(squared).chain(sqrt)
}
关于对象安全性的说明
虽然 Chained 特质在表面上看起来是 对象安全 的,因为您可以将实现 Chained 特质的现有类型转换为特质对象,但任何转换为特质对象的链都将变得无用,因为您无法对它们调用 Chained::chain
或 Chained::eval
。
Rust 的迭代器 map 方法即使在需要 Self
实现 Sized
的前提下,也可以在 trait 对象上工作。这是通过在 Box<I>
和 &mut I
上重新实现 Iterator trait 来实现的,其中 I: Iterator + ?Sized
。这是因为 Iterator 最重要的方法 next()
是对象安全的,因为它接收 &mut self
并返回 Option<Self::Item>
。另一方面,Chained 在其两个方法中都拥有 'self' 的所有权,这阻止了我们使用此类解决方案。
使 Chained 对象安全需要重大的 API 变更,我不确定这是否值得。但如果这个库的用户(如果有的话)认为特性安全性很重要,我会非常欢迎建议。如果您有建议,请随意提出问题,或者如果您想直接通过协作解决这个问题,请创建 PR。