我有很多类似下面的代码:
let metadata = Some(meta::ObjectMeta {
name: Some(apple.name.clone()),
}),
let metadata = Some(meta::ObjectMeta {
name: Some(orange.name.clone()),
}),
我希望编写一个通用函数,例如:
fn get_meta<T>(args: T) -> Option<meta::ObjectMeta> {
Some(meta::ObjectMeta {
name: Some(args.name.clone()),
})
}
let metadata = get_meta(self);
但是如何确定泛型T具有字段name
?
答案 0 :(得分:3)
当像您一样引入通用类型T
时,您将无法执行任何操作:您无法调用方法,无法访问字段等。您只是对类型一无所知。将“功能”添加到类型的唯一方法是通过特征范围,例如如果<T: Foo>
是特征,则Foo
。
因此,如果要抽象化行为,则必须编写一个捕获此行为的特征。您遇到的问题是:特征不允许指定字段。换句话说:您不能说“实现此特征的所有类型都必须具有字段name
。但是,您当然可以创建 getter方法(在Rust中,通常称为没有get
)的字段:
trait HasName {
fn name(&self) -> &str;
}
fn get_meta<T: HasName>(args: T) -> Option<meta::ObjectMeta> {
Some(meta::ObjectMeta {
name: Some(args.name().clone()),
})
}
使用吸气剂方法代替字段应该在基本上所有情况下都可以使用。
作为旁注:some early considerations关于向特征添加字段。但是,该讨论还处于早期阶段。甚至没有正式的RFC,所以不要指望很快就使用此功能。
答案 1 :(得分:1)
您不能。已经提出了这样的主张-在特征中具有虚拟领域-但目前还没有任何人接受。不过,您可以使用吸气剂,并进行一些多态处理:
struct Apple;
struct Orange;
trait Named {
fn name(&self) -> &str;
}
impl Named for Apple {
fn name(&self) -> &str {
"Golden"
}
}
impl Named for Orange {
fn name(&self) -> &str {
"Orange"
}
}
fn get_name<T>(named: T) -> String where T: Named {
named.name().to_owned()
}
fn main() {
assert_eq!(get_name(Apple), "Golden");
assert_eq!(get_name(Orange), "Orange");
}