繁体   English   中英

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

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

什么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)

与存在性类型最接近的是特征对象:

// 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);

对于特征对象,实际类型将被删除,唯一剩下的就是知道该特定值是实现给定特征的某种类型。 它与Haskell中具有类型类边界的存在类型非常相似:

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

没有办法将任意函数与任意类型捆绑在一起,从容器签名中删除它,因此您需要为其使用特征。 幸运的是,特征可以轻松地为任意类型定义和实现,因此您始终可以定义特征并使用特征对象。 特性对象涵盖了ML / Haskell中通常需要存在性的几乎所有功能。

而且,在许多情况下,您根本不需要使用特征对象! 例如,上面的print()函数实际上应编写如下:

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

该函数功能更强大,因为它可与ToString trait的任意实现程序一起使用,该实现程序包括由ToString trait对象,以及实现ToString所有其他功能。 通常,唯一使用特征对象的地方是定义异构数据结构时:

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

但是,就像我上面说的那样,当您使用特征对象时,在大多数情况下,您无需指定需要特征对象-常规的泛型函数会更惯用。

暂无
暂无

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

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