可以在安全的Rust中实现动态类型的链表吗?

xuo3flqw  于 2023-01-02  发布在  其他
关注(0)|答案(1)|浏览(132)

在safe Rust中可以实现动态类型的链表吗?
动态类型链表的含义:

Node(56.7) -> Node("hello") -> Node(77) -> ...

我这样做是作为一种练习,尝试了不同的方法都无济于事,使用特质。因此怀疑在安全生 rust 中这样做的可能性。

qzwqbdag

qzwqbdag1#

如果你的列表必须使用任何类型

您可以使用Any trait,或者更好地使用另一个对象安全trait,它具有您需要的列表中项目的功能。

enum Node {
    Nil,
    Node {
        value: Box<dyn std::any::Any>,
        next: Box<Node>,
    },
}

impl std::fmt::Debug for Node {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
        match self {
            Node::Nil => write!(f, "Nil"),
            Node::Node { value, next } => {
                if let Some(value) = value.downcast_ref::<f64>() {
                    write!(f, "Node({value}) -> {next:?}")
                } else if let Some(value) = value.downcast_ref::<i32>() {
                    write!(f, "Node({value}) -> {next:?}")
                } else if let Some(value) = value.downcast_ref::<&str>() {
                    write!(f, "Node({value:?}) -> {next:?}")
                } else {
                    write!(f, "Node(<unknown type>) -> {next:?}")
                }
            }
        }
    }
}

fn main() {
    let list = Node::Node {
        value: Box::new(56.7),
        next: Box::new(Node::Node {
            value: Box::new("hello"),
            next: Box::new(Node::Node {
                value: Box::new(77),
                next: Box::new(Node::Nil),
            }),
        }),
    };
    dbg!(list);
}

将输出类似[src/main.rs:39] list = Node(56.7) -> Node("hello") -> Node(77) -> Nil的内容到stderr。

优点

  • 可用于任何对象(实现trait)。
  • 每个Node都有两个Box的大小,无论您将什么类型放入列表。

缺点

  • 使用downcast*可能很快就会变得非常笨拙,另外,使用dyn Any也没有什么实际用途。
  • Box的必要附加间接寻址。

如果你知道列表中的类型

您可以对每种可能的类型使用枚举:

#[derive(Debug)]
enum DynamicType {
    Float(f64),
    Int(i32),
    Str(&'static str),
}
enum Node {
    Nil,
    Node {
        value: DynamicType,
        next: Box<Node>,
    },
}

impl std::fmt::Debug for Node {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
        match self {
            Node::Nil => write!(f, "Nil"),
            Node::Node { value, next } => write!(f, "Node({value:?}) -> {next:?}"),
        }
    }
}

fn main() {
    use DynamicType::*;
    let list = Node::Node {
        value: Float(56.7),
        next: Box::new(Node::Node {
            value: Str("hello"),
            next: Box::new(Node::Node {
                value: Int(77),
                next: Box::new(Node::Nil),
            }),
        }),
    };
    dbg!(list);
}

优点

  • 你可以match,并立即知道你在处理什么类型。
  • 没有间接寻址,数据直接存储在Node中。

缺点

  • 如果DynamicType包含各种大小,您可能最终会在Node上浪费大量空间。
  • 你必须知道每一种类型放在前面。

相关问题