memory - 创建一个返回空结构实现的工厂类

标签 memory struct rust heap-memory

我想为格式化程序创建一个通用接口(interface),它将接收输入并根据其目的对其进行格式化。

目前我正在返回一个包含格式化程序实现的 Box(包装到一个 Result 中)。但我认为这不是最好的方法。由于 Formatter 实现是空结构,因此为 Box 分配堆内存没有意义。

pub trait Formatter {
    fn format_information(&self, information: Result<Information, Error>) -> Result<String, Error>;
    fn format_information_collection(&self, information: InformationCollection) -> Result<String, Error>;
}

pub struct JsonFormatter;
impl Formatter for JsonFormatter {...}

pub struct XmlFormatter;
impl Formatter for XmlFormatter {...}


// Factory to create a formatter
pub struct Factory;
impl Factory {
    pub fn get_formatter(format: &str) -> Result<Box<Formatter>, Error> {
        match format {
            "json" => Ok(Box::new(JsonFormatter {})),
            "xml" => Ok(Box::new(XmlFormatter {})),
            _ => Err(Error::new(format!("No formatter found for format {}", format)))
        }
    }
}

// Use the factory
let formatter_box = Factory::get_formatter(format).unwrap();
let formatter = &*formatter_box as &Formatter;

在 Rust 中执行此操作的正确方法是什么?

最佳答案

Since the Formatter implementations are empty structs, allocating heap memory for a Box doesn't make sense.

而且由于它没有任何意义,因此根本不会分配堆内存。让我们试试看(Playground):

// `()` doesn't occupy any space, like e.g. your `JsonFormatter`
let b1 = Box::new(());
let b2 = Box::new(());

println!("{:p}\n{:p}", &*b1, &*b2);

这会产生输出:

0x1
0x1

ZST(零大小类型)通常以特殊方式处理。所以至少你知道你没有为这里的堆分配付费。但是请注意,Box<Formatter> 的内存布局是一个胖指针,看起来像这样:(*mut Formatter, *mut VTable) .第一个指针总是 0x1 ,第二个指向静态分配的调度表,其中包含函数指针(vtable - Wikipedia)。这可能适合您的情况。


另一种可能性是像这样创建一个枚举:

enum FormatterSd {
    Json(JsonFormatter),
    Xml(XmlFormatter),
}

现在您可以实现 Formatter for FormatterSd ;在此实现中,您将使用简单的 match block 做调度。这样你就不需要使用 Box .


最后:您不需要工厂类型!看起来有点像您正在尝试将强 OO 编程语言的想法带入 Rust。通常,这不是最好或最惯用的解决方案。例如,Rust 中有自由函数。所以你可以简单地写:

fn get_formatter(format: &str) -> Result<Box<Formatter>, Error> {
    // ...
}

是的,没有 Factory类型!空类型在 Rust 中比空类少得多(意思是:没有任何字段)。对于这类东西,您可以只使用自由函数,无需将其与类型相关联。

最后一点:您不需要手动从 Box 中获取引用:

let formatter = &*formatter_box as &Formatter;

你可以简单地说formatter_box.format_information(...); ,多亏了 deref 强制。

关于memory - 创建一个返回空结构实现的工厂类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43651942/

相关文章:

C - 结构和函数的前向声明

c - 将结构元素数组与另一个元素交换

rust - 将消耗树转换为非消耗树

rust - 如何在不将可变引用传递给函数的情况下重新借用它?

java - 从java获取操作系统内存大小

performance - 现代 x86-64 cpu 仍然受益于内存数据对齐吗?

c++ - 编译器的优化范围是什么?

C++ 运行时动态内存大小

c++ - 在结构 vector C++ 中搜索值的范围

rust - 使用 Transmute 的递归数据结构的零成本构建器模式。这安全吗?有更好的方法吗?