2 个版本

0.1.1 2023 年 2 月 16 日
0.1.0 2023 年 2 月 16 日

2592 in Rust 模式

MIT 许可证

15KB
150

Rust

Rust 懒加载函数链库

核心数据类型和特质模仿 Rust 的 迭代器 特质及其 map 方法。但与操作集合不同,本库中的特性和数据类型旨在处理单个值。与 Rust 中的迭代器一样,链式调用默认是 懒加载 的。

❗ Chained 目前处于实验阶段。未来的更新可能会带来破坏性变化

本库受 pipe-traitpipeline 库的启发。如果您不需要懒加载,只想简单地进行函数调用或方法调用链,上述库可能更适合您。

使用示例

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::chainChained::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。

无运行时依赖