#lens #pattern #traversing #traversal

lens-rs

Rust实现的lens

15个不稳定版本 (3个破坏性更新)

0.3.2 2021年5月7日
0.3.1 2021年4月8日
0.2.2 2021年4月3日
0.2.1 2021年3月29日
0.0.99 2021年3月20日

#1274 in Rust模式


2 crates中使用

MIT/Apache

60KB
1K SLoC

lens-rs

Rust实现的lens

  • Review光学描述了如何构造单个值。
  • Traversal可以访问多个子结构。
  • Prism可以访问可能存在的子结构。
  • Lens可以访问必须存在的子结构。

请参阅指南

示例

访问子结构

use lens_rs::*;
fn test() -> Option<()> {
    let mut nested: Result<Result<_, ()>, ()> = Review::review(optics!(Ok.Ok), (1,2));
    *x.preview_mut(optics!(Ok.Ok._0))? += 1;
    assert_eq!(nested.preview(optics!(Ok.Ok._0))?, 2);

    let mut x = (1, (2, (3, 4)));
    *x.view_mut(optics!(_1._1._1)) *= 2;
    assert_eq!(x.view(optics!(_1._1._1)), 8);

    let mut x: (_, Result<_, ()>) = (1, Ok((2, 3)));
    *x.preview_mut(optics!(_1.Ok._1))? *= 2;
    assert_eq!(x.preview(optics!(_1.Ok._1))?, 6);

    let mut x = (1, vec![Some((2, 3)), None]);
    x
        .traverse_mut(optics!(_1._mapped.Some._0))
        .into_iter()
        .for_each(|i| *i += 1);
    assert_eq!(x.traverse(optics!(_1._mapped.Some._0)), vec![3]);

    Some(())
}

为数据类型派生lens

use lens_rs::*;

#[derive(Review, Prism, Debug)]
enum AnEnum<T> {
    A(T, i32),
    #[optic] B(T),
}

#[derive(Lens, Debug)]
struct Foo {
    #[optic] a: i32,
    #[optic] b: i32,
}


fn test() -> Option<()> {
    let x = Review::review(optics!(Some.B), Foo {
        a: 3,
        b: 2,
    });
    assert_eq!(x.preview(optics!(Some.B.b))?, 2);
    
    Some(())
}

限制类型T可能有的子结构,类型是i32

fn bar<Pm, T: Prism<Pm, i32>>(t: &mut T, pm: Pm) {
    t.preview_mut(pm).map(|x| *x += 2);
}

fn test() {
    let mut complex = (1, Ok((Err(2), 3)));
    bar(&mut complex, optics!(_0));
    bar(&mut complex, optics!(_1.Err)); // do nothing
    bar(&mut complex, optics!(_1.Ok._0.Ok)); // do nothing
    bar(&mut complex, optics!(_1.Ok._0.Err));
    bar(&mut complex, optics!(_1.Ok._1));
    assert_eq!(complex, (3, Ok((Err(4), 5))));
}

限制类型T有一个字段.a

fn with_field_a<T>(t: &T) -> &str
where
    T: LensRef<Optics![a], String> // T must have .a
{
    t.view_ref(optics!(a))
}

fn may_has_c<T>(t: T) -> Option<i32>
where
    T: PrismRef<Optics![c], i32>,  // T may have field c
{
    Some(*t.preview_ref(optics!(c))?)
}

let foo = Foo {
    a: "this is Foo".to_string(),
    b: ()
};
let bar = Bar {
    a: "this is Bar".to_string(),
    c: 0
};

println!("{}", with_field_a(foo));
println!("{}", with_field_a(bar));

assert_eq!(may_has_c(foo), None);
assert_eq!(may_has_c(bar), Some(0));
assert_eq!(may_has_c(Left(0)), None);
assert_eq!(may_has_c((1, 2, 3)), None);

与structx互动

现在,Lens已为structx实现

在Cargo.toml中添加以下内容

[dependencies]
lens-rs = { version = "0.3", features = [ "structx" ] }
structx = { version = "0.1", features = [ "lens-rs" ] }

[package.metadata.inwelling]
lens-rs_generator = true
structx = true

享受它!

use structx::*;
use lens_rs::*;

let s1 = structx! { height: 1, width: 2 };
let s2 = structx! { height: 3, length: 4 };

assert_eq!(s1.view_ref(optics!(height)), &1);
assert_eq!(s2.view_ref(optics!(height)), &3);
assert_eq!(s1.preview_ref(optics!(width)), Some(&2));
assert_eq!(s2.preview_ref(optics!(width)), None);

Cargo.toml

在Cargo.toml中添加

[package.metadata.inwelling]
lens-rs_generator = true

依赖关系

~1.1–1.7MB
~41K SLoC