gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-29 07:59:53 27 4
gpt4 key购买 nike

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

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

虽然我见过 PhantomData 的其他用途,它们都被一个有趣的类型参数化了,比如 PhantomData<&'a [u8]>PhantomData<T> .您为什么要创建结构,使其表现就好像它包含一个空元组一样?

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

最佳答案

在这种情况下,剪贴板是一个全局共享资源,在您打开它时不会给您任何标记。不先打开剪贴板就尝试使用它是一件坏事。如果您做了直接的事情并创建了一个空结构,那么您可能忘记调用正确的构造函数方法:

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,但我相信有更好的解决方案 — 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

这不会生成任何警告,并且 PhantomData 用于指示正​​在发生“不同”的事情。我可能会对结构定义发表一些评论,以说明我们为何以这种方式使用 PhantomData

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

关于rust - 为什么我要创建一个只有 `PhantomData<()>` 成员的结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34603635/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com