#struct-fields #generics #functional #haskell #macro

透明性

一个 trait 库,提供访问泛型结构体内部字段的权限

5 个版本

0.0.5 2023 年 3 月 3 日
0.0.4 2023 年 3 月 3 日
0.0.3 2023 年 3 月 3 日
0.0.2 2023 年 1 月 23 日
0.0.1 2023 年 1 月 10 日

1671Rust 模式

每月 22 次下载

自定义许可

9KB

查看

License: MIT

你是否曾经偶然编写泛型代码?并在中间想要访问其中的一个字段?我们通常会使用一个 trait 并将访问行为的绑定到某个模糊的函数上,然后忘记它。我们大家都这样做过,实际上它如此普遍,以至于其他泛型和静态类型语言也提供了一种方法来做这件事。它被称为 lens 操作符。那么,为什么不把它也用于 Rust 呢。

用法

我们只需要关注三个 trait,分别是 [See][See],Load 和一个特殊的 trait [Look][Look]。在你的结构体上派生 [See][See],那么你的 struct 就为所有字段实现了 [See][See]。但它在对应的另一边不会生效,它会产生一些错误,没关系,这就是 Load trait 出现的原因。这个 trait 的唯一目的是在派生过程中加载所有找到的访问者。因此,在代码库中使用 derive [Look] 之后使用它。

这个特性让我们可以访问结构体内部的特定字段。类似于 Haskell 中的 lens。例如,考虑这样一个场景,你将一个泛型传递给一个函数,并且意外地想要获取它内部的值。假设有多个具有相同字段 foo 的结构体,你可能希望查看它。但是,由于你传递的是泛型,所以这样做是不可能的。在这里,See 就是救命稻草,如果你在一个结构体上实现 See 并使用一个单元结构体进行索引,那么你可以获取到内部的字段。但这实际上与创建一个接口以获取字段非常相似,那么问题出在哪里呢?还有一个 #[derive(See)],它会为你完成这一切。并且为了获取单元结构体,在根目录中添加 see_derive::auto_load!(),即 src/main.rssrc/lib.rs

扩展 See

虽然 [See][See] 提供了足够的访问内部字段状态的方法,但其语法对新 Rust 用户来说并不友好,也不容易理解。为了解决这个问题,实现了 [Look][Look] 特性。尽管从宏展开来看,这并不明显。实际上,它是在满足某些条件后自动实现的。

示例

查看以下示例,它将使许多事情变得清晰

use see::{See, Look, see_derive::{Look, self}};
//        ↑                       ↑
//        |                       +------ The derive
//        +----------------------------- The trait           

#[derive(Look)]
struct Point2D {
    x: i32,
    y: i32
}

#[derive(Look)]
struct Point3D {
    x: i32,
    y: i32,
    z: i32
}

// Once done using the derive or loading modules that have these derive calls do this
see_derive::auto_load!();

// Done! Now let's write a function that modifies x coordinate

fn modify_x<T>(loc: &mut T, change: i32) 
where
    T: See<see_t::X, Inner = i32> 
    // use see_t for getting the visitors and just specify your field with 2 underscores, 
    // and if need you can specify the type of inner or a morphism that's allowed on the inner type
{
    *loc.set() = change;
}

fn modify_y<T>(loc: &mut T, change: i32)
where
    T: Look<see_t::Y, Inner = i32>
    // `Look` is exactly similar to `See`
{
    loc[see_t::Y] = change;
}

fn main3d() {
    let p = Point3D {
        x: 0,
        y: 0,
        z: 0
    };
    // go left
    modify_x(&mut p, -1);
    // go right
    modify_x(&mut p, 1);
}
fn main2d() {
    let p = Point2D {
        x: 0,
        y: 0
    };
    // go left
    modify_x(&mut p, -1);
    // go right
    modify_x(&mut p, 1);
}

功能

  • 使用 See 特性获取对方法的原始访问权限
    1. fn get(&self) -> &Self::Inner 这里 inner 是问题数据的数据类型
    2. fn set(&mut self) -> &mut Self::Inner
  • 使用 Look 特性以类似的方式访问,因为它扩展了 See 特性。但它还允许更详细的访问控制,同时允许在尝试从一个泛型结构体中访问多个字段时拥有更简单的接口

贡献

  • 遵循常规注释。
  • 为任何变更请求创建问题
  • 为 PR 提供适当的参考和描述

依赖关系

~215KB