1个不稳定版本
0.1.0 | 2024年7月1日 |
---|
2169 在 过程宏
139 每月下载量
用于 ostd
16KB
110 行
自动从字段继承方法(通过过程宏)。
动机
虽然Rust在某种程度上受到了面向对象编程(OOP)范式的影响,并具有一些典型的OOP特征(如对象、封装和多态),但它不是一门OOP语言。一个证据是缺乏继承,这是OOP的重要支柱。但不要误解我:这种缺乏继承实际上是一件好事,因为它促进了Rust程序中组合优于继承的实践。尽管组合有所有这些好处,Rust程序员仍然必须编写琐碎的转发方法,这是一个繁琐的任务,尤其是当你必须编写很多的时候。
为了解决Rust中使用组合的痛点,该Crate提供了一个方便的过程宏,可以自动为你生成转发方法。换句话说,你的结构体现在可以“继承”来自其字段的方法,享受两全其美的好处:继承的便利性和组合的灵活性。
示例
实现新的类型惯用法
假设你想要创建一个名为Stack<T>
的新结构体,它可以通过简单地围绕Vec<T>
进行包装并仅公开Vec
的子集API来实现。以下是这个Crate如何帮助你轻松完成这个任务的示例。
use inherit_methods_macro::inherit_methods;
pub struct Stack<T>(Vec<T>);
// Annotate an impl block with #[inherit_methods(from = "...")] to enable automatically
// inheriting methods from a field, which is specifiedd by the from attribute.
#[inherit_methods(from = "self.0")]
impl<T> Stack<T> {
// Normal methods can be implemented with inherited methods in the same impl block.
pub fn new() -> Self {
Self(Vec::new())
}
// All methods without code blocks will "inherit" the implementation of Vec by
// forwarding their method calls to self.0.
pub fn push(&mut self, value: T);
pub fn pop(&mut self) -> Option<T>;
pub fn len(&self) -> usize;
}
如果你想要为包装类型派生常见特性(如AsRef
和Deref
),请查看shrinkwraprs crate。
模拟经典的OOP继承
在许多面向对象编程框架或应用程序中,拥有一个所有对象从中继承的基础类非常有用。在这个例子中,我们希望做同样的事情,创建一个基础类(用于接口的 Object
特性和用于实现的 ObjectBase
结构体),这样所有对象都应该“继承”。
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Mutex;
use inherit_methods_macro::inherit_methods;
pub trait Object {
fn type_name(&self) -> &'static str;
fn object_id(&self) -> u64;
fn name(&self) -> String;
fn set_name(&self, new_name: String);
}
struct ObjectBase {
object_id: u64,
name: Mutex<String>,
}
impl ObjectBase {
pub fn new() -> Self {
static NEXT_ID: AtomicU64 = AtomicU64::new(0);
Self {
object_id: NEXT_ID.fetch_add(1, Ordering::Relaxed),
name: Mutex::new(String::new()),
}
}
pub fn object_id(&self) -> u64 {
self.object_id
}
pub fn name(&self) -> String {
self.name.lock().unwrap().clone()
}
pub fn set_name(&self, new_name: String) {
*self.name.lock().unwrap() = new_name;
}
}
struct DummyObject {
base: ObjectBase,
}
impl DummyObject {
pub fn new() -> Self {
Self {
base: ObjectBase::new(),
}
}
}
#[inherit_methods(from = "self.base")]
impl Object for DummyObject {
// Give this method an implementation specific to this type
fn type_name(&self) -> &'static str {
"DummyObject"
}
// Inherit methods from the base class
fn object_id(&self) -> u64;
fn name(&self) -> String;
fn set_name(&self, new_name: String);
}
依赖关系
~2MB
~43K SLoC