Rust,反射和访问规则

Rust 语言的反射是很多人期望拥有的特性,但短期内似乎不会实现。反射与 Rust 的安全特性以一种反直觉的方式相互作用,这迫使任何反射 API 都必须遵守某些规则。

字段访问规则

在很多语言中,反射可以访问对象的所有字段,包括私有字段。但在 Rust 中,无论最终实现什么样的反射 API,都不能这样做,因为允许反射访问私有字段是根本不安全的。

反证法

Box<i32>为例,假设存在某种通过反射访问所有字段的方式,会导致安全问题,如修改Box内部的指针,使Box指向无效的内存位置,从而引发未定义行为(UB)。

内部可变性

即使是“不可变”的引用,在 Rust 中也可能导致问题,如Arc的引用计数,通过反射修改可能导致使用后释放错误。

不安全整数

修改任何私有数据都可能导致问题,如Vec的长度,简单地修改一个整数就可能造成很大的损害。

并非一切都是数字

很多 C 库给出的整数表示不透明的对象句柄,反射序列化这样的类型可能会导致崩溃。

限制反射

  • 反射标记:可以实现一个可见性标记,允许反射访问某些原本私有的字段,但这需要增加语法的繁琐性,并且需要 crate 作者明确添加反射支持。
  • 不安全字段:借鉴unsafe fields特性,将字段标记为不安全,只有非不安全的字段才能通过反射访问,但这种方式感觉有些脆弱,并且可能与之前的代码不兼容。

多米诺效应:这些限制如何影响反射

  • 为什么反射需要自定义边界:在反射序列化时,需要表达复杂的边界条件,如所有字段都可通过反射访问,每个字段类型都可序列化等。如果不添加这样的边界,在遇到错误时,编译器错误信息可能不清晰,难以确定问题所在。
  • 处理反射“失败”:明确反射的边界是最合理和用户友好的解决方案,但编写这样的边界并不容易,需要考虑各种不同的使用场景,并且要非常精确,避免出现满足边界条件但仍导致反射错误的情况。

安全与不安全的反射

  • 应该存在不安全的反射 API 吗:暴露具有更低级访问权限的不安全反射 API 有其利弊,可能会影响版本控制和代码的稳定性,但也能提供更强大的功能。同时,需要考虑安全反射获取私有字段信息可能导致的问题。
  • “安全”反射的实用性:如果反射没有访问私有字段的权限,其对代码的影响较大,可能需要将类型的定义公开,失去对数据变化的控制。与proc-macros相比,反射的优势并不明显。

总之,在 Rust 中实现反射是一个极具挑战性的问题,需要在安全和功能之间找到完美的平衡,目前还没有一个确定的解决方案。Rust 的社区需要更多的讨论和尝试,才能找到最适合 Rust 的反射实现方式。

阅读 8
0 条评论