尽管 Rust 吸收了许多优秀的现代编程思想,但似乎没有呈现一个非常基本的特性。
现代(伪)函数式代码基于大量以下类型的类:
pub struct NamedTuple {
a: i8,
b: char,
}
impl NamedTuple {
fn new(a: i8, b: char) -> NamedTuple {
NamedTuple { a: a, b: b }
}
fn a(&self) -> i8 {
self.a
}
fn b(&self) -> char {
self.b
}
}
如您所见,这里有很多样板代码。如果没有样板代码,真的没有办法紧凑地描述这些类型吗?
最佳答案
当你有样板时,想想宏:
macro_rules! ro {
(
pub struct $name:ident {
$($fname:ident : $ftype:ty),*
}
) => {
pub struct $name {
$($fname : $ftype),*
}
impl $name {
fn new($($fname : $ftype),*) -> $name {
$name { $($fname),* }
}
$(fn $fname(&self) -> $ftype {
self.$fname
})*
}
}
}
ro!(pub struct NamedTuple {
a: i8,
b: char
});
fn main() {
let n = NamedTuple::new(42, 'c');
println!("{}", n.a());
println!("{}", n.b());
}
这是一个基本宏,可以扩展以处理指定可见性以及结构和字段上的属性/文档。
我会质疑您拥有的样板文件与您认为的一样多。例如,您只显示 Copy
类型。一旦您将 String
或 Vec
添加到您的结构中,这就会分崩离析,您需要返回一个引用或获取 self
.
在编辑方面,我不认为这是好的或惯用的 Rust 代码。如果您有一个人们需要深入研究的值类型,只需将字段公开:
pub struct NamedTuple {
pub a: i8,
pub b: char,
}
fn main() {
let n = NamedTuple { a: 42, b: 'c' };
println!("{}", n.a);
println!("{}", n.b);
}
现有的 Rust 功能可以防止 getter 方法首先尝试解决的大多数问题。
基于变量绑定(bind)的可变性
n.a = 43;
error[E0594]: cannot assign to field `n.a` of immutable binding
引用规则
struct Something;
impl Something {
fn value(&self) -> &NamedTuple { /* ... */ }
}
fn main() {
let s = Something;
let n = s.value();
n.a = 43;
}
error[E0594]: cannot assign to field `n.a` of immutable binding
如果您已将值类型的所有权转让给其他人,谁在乎他们是否更改了它?
请注意,我正在对 值类型 进行区分,如 Growing Object-Oriented Software Guided by Tests 所述,它们区别于对象。对象不应有暴露的内部结构。
关于functional-programming - 如何创建没有样板代码的只读结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50929898/