war*_*ock 5 functional-programming rust
尽管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
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,这里有很多样板代码.没有样板代码,真的没有办法简单地描述这些类型吗?
She*_*ter 11
当你有样板时,请考虑宏:
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());
}
Run Code Online (Sandbox Code Playgroud)
这是一个基本宏,可以扩展为处理指定可见性以及结构和字段的属性/文档.
我要挑战你拥有和你想象的一样多的样板.例如,您只显示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);
}
Run Code Online (Sandbox Code Playgroud)
现有的Rust功能可以防止getter方法首先尝试解决的大多数问题.
基于变量绑定的可变性
n.a = 43;
Run Code Online (Sandbox Code Playgroud)
error[E0594]: cannot assign to field `n.a` of immutable binding
Run Code Online (Sandbox Code Playgroud)
参考规则
struct Something;
impl Something {
fn value(&self) -> &NamedTuple { /* ... */ }
}
fn main() {
let s = Something;
let n = s.value();
n.a = 43;
}
Run Code Online (Sandbox Code Playgroud)
error[E0594]: cannot assign to field `n.a` of immutable binding
Run Code Online (Sandbox Code Playgroud)
如果您已将值类型的所有权转让给其他人,谁会关心他们是否更改了?
请注意,我正在对由测试引导的面向对象的增长软件所描述的值类型进行区分,它们与对象区分开来.对象不应该有暴露的内部.
Rust不提供生成getter的内置方法.但是,有多个Rust功能可用于处理样板代码!对您的问题最重要的两个:
#[derive(...)]
属性自定义派生macro_rules!
(请参阅@ Shepmaster关于如何使用它们来解决问题的答案)我认为避免像这样的样板代码的最好方法是使用自定义派生.这允许您#[derive(...)]
在类型中添加属性并在编译时生成这些getter.
已经有一个箱子提供了这个:derive-getters
.它的工作原理如下:
#[derive(Getters)]
pub struct NamedTuple {
a: i8,
b: char,
}
Run Code Online (Sandbox Code Playgroud)
还有getset
,但它有两个问题:getset
应该有derive
它的箱子名称,但更重要的是,它通过提供也生成不执行任何检查的设置器来鼓励"一切的吸气剂和安装者"反模式.
最后,您可能需要考虑重新考虑Rust中的编程方法.老实说,根据我的经验,"getter样板"几乎不是问题.当然,有时候你需要编写getter,而不是"大量"的getter.
可变性在Rust中也不是单一的.Rust是一种多范式语言,支持多种编程风格.Idiomatic Rust为每种情况使用最有用的范例.完全避免变异可能不是Rust中编程的最佳方式.此外,避免可变性不仅通过为您的领域提供getter来实现 - 绑定和引用可变性更为重要!
因此,对只有它有用的字段使用只读访问权限,但不能到处使用.