我注意到 Rust 的 Vec::len
方法只是访问向量的 len
属性。为什么 len
不只是一个公共(public)属性,而不是围绕它包装一个方法?
我假设这是为了万一将来实现发生变化,不会有任何问题,因为 Vec::len
可以在没有任何 Vec< 用户的情况下改变它获取长度的方式
知道,但不知道还有没有别的原因。
我的问题的第二部分是关于我何时设计 API。如果我正在构建自己的 API,并且我有一个带有 len
属性的结构,我是否应该将 len
设为私有(private)并创建一个公共(public) len()
方法?在 Rust 中公开字段是不好的做法吗?我不这么认为,但我没有注意到在 Rust 中经常这样做。例如,我有以下结构:
pub struct Segment {
pub dol_offset: u64,
pub len: usize,
pub loading_address: u64,
pub seg_type: SegmentType,
pub seg_num: u64,
}
这些字段中的任何一个是否应该是私有(private)的,而是像 Vec
那样具有包装函数?如果是这样,那为什么呢?在 Rust 中是否有一个好的指南可以遵循?
最佳答案
一个原因是为实现某种长度概念的所有容器提供相同的接口(interface)。 (例如 std::iter::ExactSizeIterator
。)
在Vec
的情况下, len()
就像 setter/getter 一样:
impl<T> Vec<T> {
pub fn len(&self) -> usize {
self.len
}
}
虽然这确保了整个标准库的一致性,但这种设计选择背后还有另一个原因......
这个 getter 防止外部修改 len
.如果条件Vec::len <= Vec::buf::cap
永远不会满足,Vec
的方法可能会尝试非法访问内存。例如,执行 Vec::push
:
pub fn push(&mut self, value: T) {
if self.len == self.buf.cap() {
self.buf.double();
}
unsafe {
let end = self.as_mut_ptr().offset(self.len as isize);
ptr::write(end, value);
self.len += 1;
}
}
将尝试写入超过容器拥有的内存的实际末端的内存。由于这一关键要求,对 len
的修改被禁止。
哲学
在库代码中使用这样的 getter 绝对是好事(疯狂的人可能会尝试修改它!)。
但是,人们应该以一种最大限度地减少对 getter/setter 的要求的方式来设计他们的代码。一个类应该尽可能地作用于它自己的成员。这些行动应该通过方法向公众公开。在这里,我指的是做有用事情 的方法——而不仅仅是返回/设置变量的普通 ol' getter/setter。尤其是 Setter 可以通过使用构造函数或方法变得多余。 Vec
向我们展示了其中一些“ setter ”:
push
insert
pop
reserve
...
因此,Vec
实现提供对外部世界的访问的算法。但它自己管理内部。
关于methods - 为什么 Vec::len 是方法而不是公共(public)属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50661775/