【问题标题】:A built-in Object in RustRust 中的内置对象
【发布时间】:2026-02-08 16:15:01
【问题描述】:

Rust 没有内置的 Object 类型我接受它?如果是这样,我该如何创建一个“某物”的 HashMap,在 Java 中将是 Object

  fn method1(my_hash_map: HashMap<&str, ???>) { ... } // Rust
  void method1(Map<String, Object> myMap) { ... } // Java

【问题讨论】:

  • 您正在寻找any

标签: rust


【解决方案1】:

如果您想要一个可以混合多种不同类型值的 HashMap,则必须使用Any。与Map&lt;String, Object&gt; 最直接的等价物是HashMap&lt;String, Box&lt;Any&gt;&gt;。我将&amp;str 切换到String,因为没有生命周期的&amp;str 可能不是你想要的,而且无论如何从Java 中删除String 比Rust 的String 更远。

但是,如果您只是不关心值的类型,那么将method1 设为泛型会更简单、更高效:

fn method1<T>(my_hash_map: HashMap<String, T>) { ... }

当然,您也可以添加约束 T:Trait 以使用值做更多有趣的事情(参见 Object 允许相等比较和散列)。

【讨论】:

  • 为什么是Box&lt;Any&gt;,而不仅仅是Any
  • @AlexanderSupertramp Any 是一个特征,而不是具体类型。它没有已知的大小,因此您不能像类型的默认值那样按值存储它。在 Java 中也是如此,但没关系,因为无论如何所有对象都是通过引用/指针访问的。在 Rust 中,有多种指针,因此您需要决定要使用哪种:还有 &amp;'a Any,以及很快的 Rc&lt;Any&gt;Arc&lt;Any&gt; 等。
【解决方案2】:

为了扩展 rightføld 的评论,Any 是您在 Rust 中真正可以得到的最接近的,尽管它确实有一个主要限制:它由满足'static 生命周期的类型;也就是说,您不能将任何包含非静态引用的类型视为Any

第二个复杂情况是 Java 中的 Object 具有引用语义并为您提供共享所有权。因此,您需要Rc&lt;RefCell&lt;Any&gt;&gt; 之类的东西才能获得大致可比的东西。但是请注意,强烈建议不要这样做,因为它基本上会将大量检查转移到运行时。这样的事情应该是万不得已的后备。

最后,请注意,据我所知,除了已擦除类型之外,没有办法对 Any 进行动态向上转换。所以你不能引用一个实现Show的值,将其转换为&amp;Any,然后向上转换为&amp;Show

如果适用,更好的替代方案包括泛化值类型(因此使用泛型函数和结构),如果您想要支持的类型是固定的、有限的列表,则使用 enum,或者编写和实现自定义特征,按这个顺序。

但是,为了给您一个使用 Any 的示例,我将以下内容放在一起。请注意,我们必须尝试显式向上转换为每种支持的类型。

#![feature(if_let)]

use std::any::{Any, AnyRefExt};
use std::collections::HashMap;

fn main() {
    let val_a = box "blah";
    let val_b = box 42u;
    let val_c = box 3.14159f64;

    let mut map = HashMap::new();
    map.insert("a".into_string(), val_a as Box<Any>);
    map.insert("b".into_string(), val_b as Box<Any>);
    map.insert("c".into_string(), val_c as Box<Any>);

    println!("{}", map);
    splang(&map);
}

fn splang(map: &HashMap<String, Box<Any>>) {
    for (k, v) in map.iter() {
        if let Some(v) = v.downcast_ref::<&str>() {
            println!("[\"{}\"]: &str = \"{}\"", k, *v);
        } else if let Some(v) = v.downcast_ref::<uint>() {
            println!("[\"{}\"]: uint = {}", k, *v);
        } else {
            println!("[\"{}\"]: ? = {}", k, v);
        }
    }
}

运行时输出:

{c: Box<Any>, a: Box<Any>, b: Box<Any>}
["c"]: ? = Box<Any>
["a"]: &str = "blah"
["b"]: uint = 42

【讨论】: