Enum or Trait Object

栏目: IT技术 · 发布时间: 4年前

内容简介:Rust has two major mechanisms for delegating logic: enums and trait objects, and it may be unclear when to use one or the other. In this post, I will walk through how each works, what the tradeoffs are, and how to choose the right option for your code.An e

Rust has two major mechanisms for delegating logic: enums and trait objects, and it may be unclear when to use one or the other. In this post, I will walk through how each works, what the tradeoffs are, and how to choose the right option for your code.

Enums: Closed Set of Types

An enum, or enumeration is a type which can be one of several distinct variants , each possibility containing some addition data. Enums are one of Rust’s core data types, can look like any of the following, as examples:

enum Option<T> {
    Some(T),
    None,
}

enum Result<T, E> {
    Ok(T),
    Err(E),
}

enum IpAddress {
    V4(u8, u8, u8, u8),
    V6(String),
}
Code 1 A collection of example enums

Note that enums are, by their nature, a closed set of types . You define a finite list of variants, and those are the only ones which can exist. In the future, you can add variants yourself by modifying the definition of the enum type (and possibly changing call sites / users of the enum to handle the additional variant), but users of your enum type can’t add additional variants themselves.

The advantage of enums is that they are fast. Because the total list of variants is known at compile-time, selection of what code to execute based on the variant at hand is only a branch instruction.

Trait Objects: Open Set of Types

Trait Objects allow for the uniform treatment of different concrete types which all implement the same trait, like so:

use std::f64::consts::PI;

/// Defines how to get the area of a shape.
trait Area {
    fn area(&self) -> f64;
}

/// A rectangular shape with a width and height.
struct Rectangle {
    width: f64,
    height: f64,
}

impl Area for Rectangle {
    // Area for a rectangle is width times height.
    fn area(&self) -> f64 {
        self.width * self.height
    }
}

/// A circular shape with a radius.
struct Circle {
    radius: f64,
}

impl Area for Circle {
    // Area for a circle is PI * r^2
    fn area(&self) -> f64 {
        PI * self.radius * self.radius
    }
}

fn main() {
    // Make a `Vec` that holds trait objects based on the `Area`
    // trait. This lets the `Vec` hold different concrete types
    // by putting them behind a pointer, which hides what type
    // is actually there, and dispatches to the correct method
    // implementations at runtime!
    let shapes: Vec<Box<dyn Area>> = vec![
        Box::new(Rectangle { width: 2.0, height: 3.0 }),
        Box::new(Circle { radius: 4.0 })
    ];

    for shape in &shapes {
        println!("{}", shape.area());
    }
}
Code 2

By contrast, a trait object is an open set of types . Trait objects are Rust’s key mechanism for dynamic dispatch, allowing selection at runtime at which concrete type’s trait method implementation should be executed.

This dynamic dispatch does come with a cost, as the vtable must be checked to determine the location of the appropriate instructions to execute.

The advantage with trait objects is that users can define their own types which implement the trait, and can then be used wherever a trait object is expected.

Note as well that trait objects may be represented as Box<dyn Trait> (an owned trait object), or as &dyn Trait or &mut dyn Trait (borrowed trait objects). In either case, they represent an open set of types which uses dynamic dispatch for method execution.

Summarizing Trade-Offs

Table 1 Summary of trade-offs between enums and trait objects
Delegation Construct Set of Types Performance Restrictions
Enum Closed Fast (branch) N/A
Trait Object Open Slow (vtable) Object Safety

When to Use Them?

With the trade-offs understood, the question is when to use one or the other. This is going to be dependent on your context.

In general, if the need for delegation is only internal, meaning you control all the variants which may at some point need to be constructed in the future, you’re likely better off with an enum. It’s faster, subject to fewer rules (no “object safety” equivalent), and makes it easy to see a list of all the variants which may exist.

If the need for delegation is exposed externally, and you want to be maximally flexible for users of your crate, then a trait object is the better option. While you pay a performance cost for the dynamic dispatch, the flexibility gained is sometimes irreplaceable.


以上所述就是小编给大家介绍的《Enum or Trait Object》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

社交天性

社交天性

[美] 马修·利伯曼(Matthew D. Lieberman) / 贾拥民 / 浙江人民出版社 / 2016-6 / 69.90

[内容简介] ● 《社交天性》是社会心理学家马修·利伯曼解读人类“社会脑”的权威之作,它告诉我们为什么在充满合作与竞争的智慧社会中人们喜爱社交又相互连接,个人的社会影响力如何得以发挥,书中处处充满了令人惊喜的洞见。 ● 为什么有的人天生善于社交,而有的人总是充满障碍? 为什么智商越高的人越难相处? 心痛对人的伤害甚至超过头痛? 慈善组织如何激发人们的捐赠行为? ......一起来看看 《社交天性》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具