为新类型实现Deref是否被认为是不好的做法? [英] Is it considered a bad practice to implement Deref for newtypes?

查看:85
本文介绍了为新类型实现Deref是否被认为是不好的做法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我经常使用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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆