为新类型实现Deref是否被认为是不好的做法? [英] Is it considered a bad practice to implement Deref for newtypes?
问题描述
我经常使用newtype模式,但是我厌倦了编写 my_type.0.call_to_whatever(...)
。我很想实现 Deref
特质,因为它允许编写更简单的代码,因为在某些情况下,例如 eg em>:
I often use the newtype pattern, but I am tired of writing my_type.0.call_to_whatever(...)
. I am tempted to implement the Deref
trait because it permits writing simpler code since I can use my newtype as if it were the underlying type in some situations, e.g.:
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
}
一样使用my_array这是一个好还是不好的做法?为什么?缺点是什么?
Is this a good or bad practice? Why? What can be the downsides?
推荐答案
我认为这是不良做法。
因为在某些情况下我可以使用新类型,就好像它是基础类型一样
since I can use my newtype as if it were the underlying type in some situations
这就是问题所在–只要有引用,它就可以隐式用作基础类型 。如果实现 DerefMut
,那么它在需要可变引用时也适用。
That's the problem — it can be implicitly used as the underlying type whenever a reference is. If you implement DerefMut
, then it also applies when a mutable reference is needed.
您没有任何引用控制基础类型的可用和不可用;一切都是。在您的示例中,您是否要允许人们呼叫 as_ptr
? sort
?我肯定希望您能这样做,因为它们可以!
You don't have any control over what is and what is not available from the underlying type; everything is. In your example, do you want to allow people to call as_ptr
? What about sort
? I sure hope you do, because they can!
关于您所能做的就是尝试覆盖方法,但它们仍然必须存在:
About all you can do is attempt to overwrite methods, but they still have to exist:
impl MyArray {
fn as_ptr(&self) -> *const i32 {
panic!("No, you don't!")
}
}
即使如此,它们仍然可以显式调用(< [i32]> :: as_ptr(& * my_array);
)。
Even then, they can still be called explicitly (<[i32]>::as_ptr(&*my_array);
).
出于同样的原因,我认为使用继承进行代码重用是一种不好的做法,因此我认为这是不好的做法。在您的示例中,您实质上是从数组继承。我绝不会写类似以下Ruby的代码:
I consider it bad practice for the same reason I believe that using inheritance for code reuse is bad practice. In your example, you are essentially inheriting from an array. I'd never write something like the following Ruby:
class MyArray < Array
# ...
end
这回到 is-a 和 has-a 概念。是 MyArray
一个数组吗?应该可以在数组可以使用的任何地方使用它们吗?它是否有先决条件,那就是对象应该坚持消费者不应该能够破坏?
This comes back to the is-a and has-a concepts from object-oriented modeling. Is MyArray
an array? Should it be able to be used anywhere an array can? Does it have preconditions that the object should uphold that a consumer shouldn't be able to break?
但是我对写
my_type.0.call_to_whatever(...)
就像其他语言一样,我相信正确的解决方案是组成而不是继承。如果您需要转接呼叫,请在新类型上创建一个方法:
Like in other languages, I believe the correct solution is composition over inheritance. If you need to forward a call, create a method on the newtype:
impl MyArray {
fn call_to_whatever(&self) { self.0.call_to_whatever() }
}
使Rust痛苦的是缺少代理。 假设的委托语法可能类似于
The main thing that makes this painful in Rust is the lack of delegation. A hypothetical delegation syntax could be something like
impl MyArray {
delegate call_to_whatever -> self.0;
}
因此,当应该时,您使用 Deref
/ DerefMut
?我主张只有在实现智能指针时才有意义。
So when should you use Deref
/ DerefMut
? I'd advocate that the only time it makes sense is when you are implementing a smart pointer.
实际上,我做使用 Deref
/ DerefMut
表示<在我是唯一或主要贡献者的项目上公开暴露的不是我的强人。这是因为我信任自己,并且对我的意思有很好的了解。如果存在委托语法,我就不会。
Speaking practically, I do use Deref
/ DerefMut
for newtypes that are not exposed publicly on projects where I am the sole or majority contributor. This is because I trust myself and have good knowledge of what I mean. If delegation syntax existed, I wouldn't.
这篇关于为新类型实现Deref是否被认为是不好的做法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!