简体   繁体   English

如何使用Rust枚举,结构,特征或其他任何东西来构造包含存在类型的值?

[英]How can I use a Rust enum, struct, trait or anything else to construct a value containing an existential type?

What Rust construct roughly accomplishes the same thing as the following OCaml? 什么Rust构造可以大致完成与以下OCaml相同的任务?

type t = F : 'x * ('x -> string) -> t

let int_eg = F(1, string_of_int)
let str_eg = F("foo", fun x -> x)

let print x = print_string (match x with
  | F(x,to_str) -> to_str x)

The closest thing you can get to existential types are trait objects: 与存在性类型最接近的是特征对象:

// how ToString is declared
trait ToString {
    fn to_string(&self) -> String;
}

let i32_str: Box<ToString> = Box::new(1);
let str_str: Box<ToString> = Box::new("foo");

fn print(value: &ToString) -> String {
    value.to_string()
}
print_x(&i32_str);  // automatically coerced from Box<ToString> to &ToString
print_x(&str_str);

With trait objects, the actual type is erased, and the only thing that remains is the knowledge that this particular value is of some type which implements the given trait. 对于特征对象,实际类型将被删除,唯一剩下的就是知道该特定值是实现给定特征的某种类型。 It is very similar to existential types with type class bounds in Haskell: 它与Haskell中具有类型类边界的存在类型非常相似:

data Showable = Showable (forall a. Show a => a)

There is no way to bundle an arbitrary function with an arbitrary type, erasing it from the container signature, so you need to use a trait for it. 没有办法将任意函数与任意类型捆绑在一起,从容器签名中删除它,因此您需要为其使用特征。 Fortunately, traits are easy to define and implement for arbitrary types, so you can always define a trait and use a trait object. 幸运的是,特征可以轻松地为任意类型定义和实现,因此您始终可以定义特征并使用特征对象。 Trait objects cover almost all functionality for which existentials are usually needed in ML/Haskell. 特性对象涵盖了ML / Haskell中通常需要存在性的几乎所有功能。

Moreover, in many cases you don't need to work with trait objects at all! 而且,在许多情况下,您根本不需要使用特征对象! For example, the print() function above should actually be written as follows: 例如,上面的print()函数实际上应编写如下:

fn print<T: ToString>(value: &T) -> String {
    value.to_string()
}

Such function is much more powerful because it works with arbitrary implementors of ToString trait, which include trait objects made out of ToString but also everything else which implements ToString . 该函数功能更强大,因为它可与ToString trait的任意实现程序一起使用,该实现程序包括由ToString trait对象,以及实现ToString所有其他功能。 The only place you usually use trait objects is when you define heterogeneous data structures: 通常,唯一使用特征对象的地方是定义异构数据结构时:

let many_to_strings: Vec<Box<ToString>> = vec![Box::new(1), Box::new("foo")];

But, as I said above, when you consume trait objects, in most cases you don't need to specify that you need a trait object - a regular generic function would be more idiomatic. 但是,就像我上面说的那样,当您使用特征对象时,在大多数情况下,您无需指定需要特征对象-常规的泛型函数会更惯用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM