#row #polymorphism #anonymous #structural

rovv

为 Rust 提供匿名行类型(穷人版的行多态)

4 个版本

0.2.1 2021 年 5 月 27 日
0.2.0 2021 年 4 月 9 日
0.1.1 2021 年 3 月 30 日
0.1.0 2021 年 3 月 30 日

#1774Rust 模式

MIT/Apache

20KB
270

概述

rovv 是一个 crate,用于为 Rust 提供“穷人版”的基于 lens-rs 的行多态。

什么是行多态?

在编程语言类型理论中,行多态是一种多态,允许编写在记录字段类型(也称为行)上多态的程序。

-- 维基百科

考虑一个 PureScript 中的函数

\r -> r.x

你可以将一个记录传递到上面的函数中

{ x: 1 }

甚至

{ x: 1, y: 2, z: 3 }

这就是“行多态”的含义:只要记录包含一个字段 .x,就可以将其传递到上面的函数中。

函数的类型是

{ x: a | l } -> a
-- The label `l` represents the rest fields of a record.

现在你可以在 Rust 中做同样的(不完全相同)事情。

用法

限制参数 r 包含字段 .x

fn take_x<T>(r: row! { x: T, .. }) -> T {
    r.view(optics!(x))
}

// &row! { x: T, .. } is ok
fn take_x_ref<T>(r: &row! { ref x: T, .. }) -> &T {
    r.view_ref(optics!(x))
}

// &mut row! { x: T, .. } is ok
fn take_x_mut<T>(r: &mut row! { mut x: T, .. }) -> &mut T {
    r.view_mut(optics!(x))
}

let foo = Foo { // have been derived Lens for Foo
    x: String::from("this is Foo"),
    y: 1234
}

let bar = Bar { // have been derived Lens for Bar
    x: 0,
    z: Some(1)
}

assert_eq!(&*take_x_ref(&foo), "this is Foo");
assert_eq!(take_x(bar), 0);

你也可以描述一个类型 可能 包含一个字段

fn or_take_y<T>(r: row! { y: T?, .. }) -> Option<T> {
    r.preview(optics!(y))
}

assert_eq!(or_take_y(foo), Some(1234));
assert_eq!(or_take_y(bar), None);

展开

函数 take_x 等价于

fn take_x<T, R>(r: R) -> T
where
    R: Lens<Optics![x], T>
{
    r.view(optics!(x))
}

实际上,row! { .. } 将展开为 impl trait,满足 lens trait 的类型占位符。而 dyn_row! { .. } 将展开为 dyn trait,row! 的动态版本。

fn sum_field(n: i32) -> Box<dyn_row! { Ok: i32?, Err: String?, Some: ()? , ..}> {
    match n%3 {
        0 => Box::new(Result::<_, String>::Ok(0)),
        1 => Box::new(Result::<i32, _>::Err(String::from("no!"))),
        2 => Box::new(Some(())),
        _ => Box::new(Option::<()>::None)
    }
}

限制

  • row! 在参数位置使用时,不能显式地将泛型参数传递到函数中,因为 row! 是 impl trait。
  • dyn_row! 将失去一些多态性,例如 dyn_row! { x: i32, .. } 不满足 dyn_row! { ref x: i32, .. },因为 trait 对象无法转换为其他类型,即使 Trait1: Trait2。
  • 不能从 dyn_row! 中移动出一个字段。

Cargo.toml

请在您的 Cargo.toml 中添加以下内容:

[dependencies]
lens-rs = "0.3"
rovv = "0.2"

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

祝您使用愉快!

依赖项

~1.2–1.8MB
~43K SLoC