在 Rust 中实现类似于 C++ 的 'std::remove_reference' 的东西?



如果类型是引用,我想有一个工具从类型中删除引用。像这样的东西(伪代码(:

remove_ref(i32)      == i32
remove_ref(&i32)     == i32
remove_ref(&&i32)    == i32
remove_ref(&mut i32) == i32

C++在标准库中std::remove_reference可以完全按照我的意愿进行操作。我试图在 Rust 中实现相同的内容,但我无法让它工作。目前,在 Rust 中"输出"类型的唯一方法是特征上的关联类型(我认为(。我尝试了这样的东西(游乐场(:

#![feature(specialization)]
trait RemoveRef {
type WithoutRef;
}
default impl<T> RemoveRef for T {
type WithoutRef = T;
}
impl<'a, T: RemoveRef> RemoveRef for &'a T {
type WithoutRef = T::WithoutRef;
}

事实上,这是编译的。有为!(是的,这还没有考虑可变引用(。但是,当我尝试使用它时,一切都会爆炸:

let _: <i32 as RemoveRef>::WithoutRef = 3;
let _: <&i32 as RemoveRef>::WithoutRef = 3;
let _: <&&i32 as RemoveRef>::WithoutRef = 3;

第一行导致"溢出评估需求i32: RemoveRef"。另外两行产生错误"不满足绑定&i32: RemoveRef的特征"。我不确定我只是不明白这一点还是专业化被打破了。(相关:我在这里遇到了另一个奇怪的错误,代码非常相似(

我在考虑实现这一点的其他可能性:也许在特征上放置一个类型参数?也许 GAT 可以在这里提供帮助?语言中是否有其他功能允许从一种类型映射到另一种类型?

有没有办法在 Rust 中实现这样的东西?

这是一种无需专用化功能的简单方法:

use std::marker::PhantomData;
trait RemoveRef {
type WithoutRef;
}
struct Ref<T> {
phantom: PhantomData<T>,
}
impl<T> RemoveRef for Ref<T> {
type WithoutRef = T;
}
impl<'a, T: RemoveRef> RemoveRef for &'a T {
type WithoutRef = T::WithoutRef;
}
fn main() {
let _: <Ref<i32> as RemoveRef>::WithoutRef = 3;
let _: <&Ref<i32> as RemoveRef>::WithoutRef = 3;
let _: <&&&&Ref<i32> as RemoveRef>::WithoutRef = 3;
}

不确定它是否可以以这种形式与您的实际用例兼容,或者它是否有用。

或者,当然也可以用具体类型的实现替换通用退出条件(impl<T> RemoveRef for T(:

impl RemoveRef for i32 {
type WithoutRef = Self;
}

这将启用原始测试代码:

let _: <i32 as RemoveRef>::WithoutRef = 3;
let _: <&i32 as RemoveRef>::WithoutRef = 3;
let _: <&&i32 as RemoveRef>::WithoutRef = 3;

AFAIK 专业化无法帮助您解决重叠问题,例如此时for Tfor &'a T之间的问题。它需要负特征边界等特征。

default impl中的所有项都是隐式默认值。如果将default关键字移动到代码中的关联类型,则会消除计算溢出,但会收到其他错误:

impl<T> RemoveRef for T {
default type WithoutRef = T;
}
error[E0308]: mismatched types
--> src/main.rs:16:45
|
16 |     let _: <i32 as RemoveRef>::WithoutRef = 3;
|                                             ^ expected associated type, found integral variable
|
= note: expected type `<i32 as RemoveRef>::WithoutRef`
found type `{integer}`

此操作失败的原因与此处讨论的原因相同: 仅当 impl 标记为 impl 时,关联类型和类型参数之间不匹配defaultTdefault一起分配给WithoutRef不会限制WithoutRef键入T

最新更新