searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Rust虚类型参数

2025-12-05 09:22:03
1
0

Rust虚类型参数

虚类型参数用来解决这种情况:一个泛型类型的参数从语义上非常重要,但结构体里却不需要存放这种类型的实际数据。换句话说,这种类型 只在类型层面上存在,在运行时不存在。
Rust 为此提供了一个轻量级标记:PhantomData<T>。
它本质是“在类型系统中声明:我与 T 有关联”,但运行时不会实际占用空间。

1. PhantomStruct:与不存在的类型建立语义关系

示例结构体:

pub struct PhantomStruct<A, B> {
    first: A,
    phantom: PhantomData<B>,
}

这里 B 虽然没有真实字段参与,但你明确告诉编译器:

这个结构体和 B 类型有关,不要把我当作没有这个参数的普通 A 结构体。

例如:

let a: PhantomStruct<i32, char> = PhantomStruct::new(12);
let b: PhantomStruct<i32, f64> = PhantomStruct::new(12);

两个值的内容完全一样,只存了 i32,但 类型绝对不同。所以:

a == b    // 完全不允许,因为类型不同

这就是PhantomData最根本的价值:为类型添加“逻辑上的标签”。

2. 虚类型参数在构造函数中的体现

构造器:

impl<A, B> PhantomStruct<A, B> {
    pub fn new(first: A) -> PhantomStruct<A, B> {
        PhantomStruct {
            first,
            phantom: PhantomData
        }
    }
}

调用时B 必须由上下文(如变量类型)提供,否则编译器无法知道 B 是什么。

3. PhantomData用来实现“单位检查”

两个空的枚举表示单位:

enum Yuan {}
enum Dollar {}

然后写一个 Money<Currency> 结构体:

struct Money<Currency> {
    amount: f64,
    currency: PhantomData<Currency>,
}

通过这里的PhantomData,我们可以告诉编译器:

Money<Yuan> 和 Money<Dollar> 是两种不一样的类型

为Money实现Add方法:

impl<Currency> Add for Money<Currency> {
    type Output = Money<Currency>;
    fn add(self, rhs: Money<Currency>) -> Money<Currency> {
        Money {
            amount: self.amount + rhs.amount,
            currency: PhantomData
        }
    }
}

值得注意的是,这里的Add必须要求同一种Currency才能相加。
这意味着:

let chinese: Money<Yuan> = Money { amount: 100.0, currency: PhantomData };
let american: Money<Dollar> = Money { amount: 10.0, currency: PhantomData };

let ok1 = chinese + chinese;            // ✓
let ok2 = american + american;        // ✓

let error = chinese + american;       // ✗ 编译失败!

两个 f64 明明都能加,但由于 PhantomData 定义的“类型标签”,
Rust 从类型层面阻止了逻辑错误。这就是 零运行成本的类型安全,非常 Rust。

0条评论
作者已关闭评论
陈****然
14文章数
0粉丝数
陈****然
14 文章 | 0 粉丝
陈****然
14文章数
0粉丝数
陈****然
14 文章 | 0 粉丝
原创

Rust虚类型参数

2025-12-05 09:22:03
1
0

Rust虚类型参数

虚类型参数用来解决这种情况:一个泛型类型的参数从语义上非常重要,但结构体里却不需要存放这种类型的实际数据。换句话说,这种类型 只在类型层面上存在,在运行时不存在。
Rust 为此提供了一个轻量级标记:PhantomData<T>。
它本质是“在类型系统中声明:我与 T 有关联”,但运行时不会实际占用空间。

1. PhantomStruct:与不存在的类型建立语义关系

示例结构体:

pub struct PhantomStruct<A, B> {
    first: A,
    phantom: PhantomData<B>,
}

这里 B 虽然没有真实字段参与,但你明确告诉编译器:

这个结构体和 B 类型有关,不要把我当作没有这个参数的普通 A 结构体。

例如:

let a: PhantomStruct<i32, char> = PhantomStruct::new(12);
let b: PhantomStruct<i32, f64> = PhantomStruct::new(12);

两个值的内容完全一样,只存了 i32,但 类型绝对不同。所以:

a == b    // 完全不允许,因为类型不同

这就是PhantomData最根本的价值:为类型添加“逻辑上的标签”。

2. 虚类型参数在构造函数中的体现

构造器:

impl<A, B> PhantomStruct<A, B> {
    pub fn new(first: A) -> PhantomStruct<A, B> {
        PhantomStruct {
            first,
            phantom: PhantomData
        }
    }
}

调用时B 必须由上下文(如变量类型)提供,否则编译器无法知道 B 是什么。

3. PhantomData用来实现“单位检查”

两个空的枚举表示单位:

enum Yuan {}
enum Dollar {}

然后写一个 Money<Currency> 结构体:

struct Money<Currency> {
    amount: f64,
    currency: PhantomData<Currency>,
}

通过这里的PhantomData,我们可以告诉编译器:

Money<Yuan> 和 Money<Dollar> 是两种不一样的类型

为Money实现Add方法:

impl<Currency> Add for Money<Currency> {
    type Output = Money<Currency>;
    fn add(self, rhs: Money<Currency>) -> Money<Currency> {
        Money {
            amount: self.amount + rhs.amount,
            currency: PhantomData
        }
    }
}

值得注意的是,这里的Add必须要求同一种Currency才能相加。
这意味着:

let chinese: Money<Yuan> = Money { amount: 100.0, currency: PhantomData };
let american: Money<Dollar> = Money { amount: 10.0, currency: PhantomData };

let ok1 = chinese + chinese;            // ✓
let ok2 = american + american;        // ✓

let error = chinese + american;       // ✗ 编译失败!

两个 f64 明明都能加,但由于 PhantomData 定义的“类型标签”,
Rust 从类型层面阻止了逻辑错误。这就是 零运行成本的类型安全,非常 Rust。

文章来自个人专栏
文章 | 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0