为什么我要创建一个只有`PhantomData<()>`成员的结构?

时间:2016-01-05 03:15:50

标签: rust

在阅读the answer for another question时,我看到了这个构造[1]:

struct Clipboard {
    marker: PhantomData<()>,
}

虽然我已经看到了PhantomData的其他用途,但所有这些用户都使用了有趣的类型进行参数化,例如PhantomData<&'a [u8]>PhantomData<T>。你为什么要创建行为的结构,好像它包含一个空元组?

[1]:有点诗意的许可,因为我实际上写了另一个答案,但被要求解释为什么我做了我做的。评论太长了。

1 个答案:

答案 0 :(得分:3)

在这种情况下,剪贴板是一个全局共享资源,在您打开它时没有给您任何令牌。要尝试使用剪贴板而不先打开它将是一件坏事。如果你做了直截了当的事情并创建了一个空结构,那么你可以忘记来调用正确的构造函数方法:

struct Clipboard;

impl Clipboard {
    fn new() -> Clipboard {
        println!("Clipboard opened");
        Clipboard
    }

    fn copy(&self) -> String { "copied".into() }
}

let c = Clipboard::new(); // Correct
println!("{}", c.copy());
let c = Clipboard;        // Nope, didn't open the clipboard properly
println!("{}", c.copy()); // But can still call methods!?!?!

让我们尝试一个带有虚拟值的元组结构:

struct ClipboardWithDummyTuple(());

impl ClipboardWithDummyTuple {
    fn new() -> ClipboardWithDummyTuple {
        println!("Clipboard opened");
        ClipboardWithDummyTuple(())
    }

    fn copy(&self) -> String { "copied".into() }
}

let c = ClipboardWithDummyTuple::new(); // Correct
println!("{}", c.copy());
let c = ClipboardWithDummyTuple;
println!("{}", c.copy()); // Fails here
// But because `c` is a method, not an instance              

这样更好,但错误发生的时间晚于我们的喜欢;它只发生在我们尝试使用剪贴板时,而不是在我们尝试构建剪贴板时。让我们尝试使用命名字段创建一个结构:

struct ClipboardWithDummyStruct { 
    // warning: struct field is never used
    dummy: (),
}

impl ClipboardWithDummyStruct {
    fn new() -> ClipboardWithDummyStruct {
        println!("Clipboard opened");
        ClipboardWithDummyStruct { dummy: () }
    }

    fn copy(&self) -> String { "copied".into() }
}

let c = ClipboardWithDummyStruct::new(); // Correct
println!("{}", c.copy());
let c = ClipboardWithDummyStruct; // Fails here
// But we have an "unused field" warning

所以,我们离得更近了,但这会产生关于未使用字段的警告。我们可以关闭#[allow(dead_code)]字段的警告,或者我们可以将字段重命名为_dummy,但我相信这是一个更好的解决方案 - {{1 }}:

PhantomData

这不会产生任何警告,use std::marker::PhantomData; struct ClipboardWithPhantomData { marker: PhantomData<()>, } impl ClipboardWithPhantomData { fn new() -> ClipboardWithPhantomData { println!("Clipboard opened"); ClipboardWithPhantomData { marker: PhantomData } } fn copy(&self) -> String { "copied".into() } } let c = ClipboardWithPhantomData::new(); // Correct println!("{}", c.copy()); let c = ClipboardWithPhantomData; // Fails here 用于表示某些内容&#34;不同&#34;正在发生。我可能会对结构定义发表一点评论,以便注意我们以这种方式使用PhantomData的原因。

这里的很多想法源于半相关的Rust issue about the correct type for an opaque struct