我经常使用newtype模式,但我厌倦了写作my_type.0.call_to_whatever(...).我很想实现这个Deref特性,因为它允许编写更简单的代码,因为我可以使用我的newtype,好像它在某些情况下是底层类型,例如:
use std::ops::Deref;
type Underlying = [i32; 256];
struct MyArray(Underlying);
impl Deref for MyArray {
type Target = Underlying;
fn deref(&self) -> &Self::Target {
&self.0
}
}
fn main() {
let my_array = MyArray([0; 256]);
println!("{}", my_array[0]); // I can use my_array just like a regular array
}
Run Code Online (Sandbox Code Playgroud)
这是一种好的还是坏的做法?为什么?可能是什么缺点?
She*_*ter 20
我认为这是一个不好的做法.
因为在某些情况下我可以使用我的newtype,就好像它是底层类型一样
这就是问题 - 只要引用它就可以隐式地用作底层类型.如果实现DerefMut,则在需要可变引用时也适用.
您无法控制基础类型的内容和内容; 一切都是.在你的例子中,你想让人们打电话as_ptr吗?怎么样sort?我当然希望你这样做,因为他们可以!
关于你所能做的就是尝试覆盖方法,但它们仍然必须存在:
impl MyArray {
fn as_ptr(&self) -> *const i32 {
panic!("No, you don't!")
}
}
Run Code Online (Sandbox Code Playgroud)
即使这样,它们仍然可以被明确地调用(<[i32]>::as_ptr(&*my_array);).
我认为这是不好的做法,因为我认为使用继承代码重用是不好的做法.在您的示例中,您基本上是从数组继承.我永远不会写类似下面的Ruby:
class MyArray < Array
# ...
end
Run Code Online (Sandbox Code Playgroud)
这回到了is-a并且具有面向对象建模的概念.是MyArray 阵列?它应该可以在阵列可以使用的任何地方使用吗?是否有先决条件,对象应该坚持消费者不应该破坏?
但我厌倦了写作
my_type.0.call_to_whatever(...)
与其他语言一样,我认为正确的解决方案是继承的组合.如果您需要转发呼叫,请在newtype上创建一个方法:
impl MyArray {
fn call_to_whatever(&self) { self.0.call_to_whatever() }
}
Run Code Online (Sandbox Code Playgroud)
使Rust痛苦的主要原因是缺乏授权.一个假想的代表团语法是像
impl MyArray {
delegate call_to_whatever -> self.0;
}
Run Code Online (Sandbox Code Playgroud)
那么什么时候应该使用Deref/ DerefMut?我主张唯一有意义的是你实现一个智能指针.
实际上,我确实使用Deref/ DerefMut用于在我作为唯一或多数贡献者的项目中不公开暴露的新类型.这是因为我相信自己,并且对我的意思有很好的了解.如果存在委托语法,我就不会.
Dan*_*iel 14
与公认的答案相反,我发现一些流行的板条箱实现了Deref新类型而不是智能指针的类型:
actix_web::web::Json<T>是一个元组结构(T,)并且它实现了Deref<Target=T>.
bstr::BString输入一个字段Vec<u8>并实现Deref<Target=Vec<u8>>.
所以,也许只要不被滥用就可以了,例如模拟多级继承层次结构。我还注意到上面的两个示例要么有零个公共方法,要么只有一个into_inner返回内部值的方法。因此,保持包装类型的方法数量最少似乎是个好主意。
| 归档时间: |
|
| 查看次数: |
2542 次 |
| 最近记录: |