【问题标题】:How can I get same result of `std::any::TypeId::of` over `T`, `&T` and `&mut` T in Rust?如何在 Rust 中通过 `T`、`&T` 和 `&mut` T 获得相同的 `std::any::TypeId::of` 结果?
【发布时间】:2021-03-08 04:51:56
【问题描述】:

我想为实现Sized + 'static 的给定类型T 获取TypeId 的一些实例。

use std::any::TypeId;

trait Comp: Sized + 'static { }

impl<T: 'static> Comp for T { }

struct Foo;

fn main() {
    println!("{}", TypeId::of::<Foo>());
    println!("{}", TypeId::of::<&Foo>());
    println!("{}", TypeId::of::<&mut Foo>());
}

但结果不同。是的,我知道这是完全正常的行为。为了处理这个问题,我修改了这段代码如下。

use std::ops::Deref;

// Same codes are omitted...

fn main() {
    println!("{}", TypeId::of::<Foo>());
    println!("{}", TypeId::of::<<&Foo as Deref>::Target>());
    println!("{}", TypeId::of::<<&mut Foo as Deref>::Target>());
}

现在它打印相同的值。为了对所有Comp 实现这种行为,我在下面写了。

use std::any::TypeId;
use std::ops::Deref;

trait Comp: Sized + 'static {
   type Pure: Comp;
}

impl<T: 'static> Comp for T {
   type Pure = T;
}

impl<T: Deref + 'static> Comp for T {
    type Pure = <T as Deref>::Target;
}

struct Foo;

fn main() {
    println!("{}", TypeId::of::<<Foo as Comp>::Pure>());
    println!("{}", TypeId::of::<<&Foo as Comp>::Pure>());
    println!("{}", TypeId::of::<<&mut Foo as Comp>::Pure>());
}

它不会编译,因为我提供了相互冲突的实现。我该如何解决这个问题?

【问题讨论】:

  • 你打算用TypeId 做什么,它可能与你手头的类型相对应或不对应?
  • 这需要仅对类型进行操作(即“静态”方法),还是可以对值使用方法?
  • 这似乎是 specialization 的教科书用法,遗憾的是尚未稳定(或接近稳定)。
  • 即使在夜间,你也不能专门“研究”一个特征。可以通过How can I write a method to wrap any value in my type that can be called multiple times without requiring type annotations? 解决(使用P: Deref&lt;Target = T&gt; 而不是Wrapper&lt;T&gt;
  • 但我怀疑这是一件有用的事情;正如我之前问过的,如果您不知道 TypeId 属于什么类型,您将如何处理它?你不能透明地对待&amp;TT,所以你不能通过Any向上/向下转换。我想你可以用它索引地图吗?但这似乎只是将问题推高了一个层次,因为您获得的任何价值都将是 either T&amp;T 而不是两者。这听起来很奇怪,就像你试图想象引用并不真正存在。我鼓励你不要这样做,并寻找替代方法来做你正在做的任何事情。

标签: types rust


【解决方案1】:

我终于在 Rust 的官方社区找到了解决方案。可以通过specialization不稳定的特性来实现。

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=4c5f206ef3a7843ed57c256ee73ac58c

#![feature(specialization)]
use std::any::TypeId;
use std::ops::Deref;

trait Comp: Sized {
   type Pure: Comp;
}

impl<T> Comp for T {
   default type Pure = T;
}

impl<T: Deref> Comp for T where <T as Deref>::Target: Comp {
    type Pure = <T as Deref>::Target;
}

struct Foo;

fn main() {
    println!("{:?}", TypeId::of::<<Foo as Comp>::Pure>());
    println!("{:?}", TypeId::of::<<&Foo as Comp>::Pure>());
    println!("{:?}", TypeId::of::<<&mut Foo as Comp>::Pure>());
}

【讨论】:

    猜你喜欢
    • 2020-09-12
    • 1970-01-01
    • 1970-01-01
    • 2023-01-20
    • 1970-01-01
    • 1970-01-01
    • 2010-10-02
    • 1970-01-01
    • 2022-08-16
    相关资源
    最近更新 更多