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 日 |
#1774 在 Rust 模式
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