Point并Vec2使用相同的变量和完全相同的构造函数定义:
pub struct Point {
pub x: f32,
pub y: f32,
}
pub struct Vec2 {
pub x: f32,
pub y: f32,
}
impl Point {
pub fn new(x: f32, y: f32) -> Self {
Self { x, y }
}
}
impl Vec2 {
pub fn new(x: f32, y: f32) -> Self {
Self { x, y }
}
}
Run Code Online (Sandbox Code Playgroud)
是否可以定义一个特征来实现构造函数?
到目前为止,我发现只能定义接口,因为内部变量未知:
pub trait TwoDimensional {
fn new(x: f32, y: f32) -> Self;
}
Run Code Online (Sandbox Code Playgroud)
您当然可以定义这样的特征,并为您的 2 个结构实现它,但是您必须编写两次实现。尽管特征可以提供函数的默认实现,但以下内容将不起作用:
trait TwoDimensional {
fn new(x: f32, y: f32) -> Self {
Self {
x,
y,
}
}
}
Run Code Online (Sandbox Code Playgroud)
原因很简单。i32如果您为or()或 an实现此特征会发生什么enum?
特征从根本上来说没有关于实现它们的底层数据结构的信息。Rust 不支持 OOP,并且试图强制它通常会导致丑陋、不惯用和性能较差的代码。
但是,如果您有一堆结构并且想要本质上“impl多次写入相同的内容而不复制/粘贴”,那么宏可能会很有用。这种模式在标准库中很常见,例如,其中有一些为所有整数类型实现的函数。例如:
macro_rules! impl_constructor {
($name:ty) => {
impl $name {
pub fn new(x: f32, y: f32) -> Self {
Self {
x, y
}
}
}
}
}
impl_constructor!(Point);
impl_constructor!(Vec2);
Run Code Online (Sandbox Code Playgroud)
这些宏在编译时扩展,因此如果您执行了无效的操作(例如impl_constructor!(i32),您将收到编译错误,因为宏扩展将包含i32 { x, y }.
就我个人而言,我仅在确实有大量类型需要实现时才使用宏。这只是个人喜好,但是手写块和宏生成impl块之间没有运行时差异。