有可能拥有一个动态通用特征的集合吗



我有一个带有泛型类型参数的特性。我想把实现这个特性的不同对象放在一个集合中。对象具有不同的类型参数。

当我这样做时,编译器告诉我需要指定泛型类型参数。事实上,我的案例不需要这些通用类型信息,所以某种通配符对我有用。让我展示代码,因为它更好地显示了我的意图:

trait Test<T> {
fn test(&self) -> T;
}
struct Foo;
struct Bar;
impl Test<i64> for Foo {
fn test(&self) -> i64 {
println!("foo");
42
}
}
impl Test<String> for Bar {
fn test(&self) -> String {
println!("bar");
"".to_string()
}
}
fn main() {
// I'm not going to invoke test method which uses generic type parameter.
// So some kind of wildcard would work for me.
// But underscore is not wildcard and this does not compile.
let xs: Vec<Box<dyn Test<_>>> = vec![Box::new(Foo), Box::new(Bar)];
xs.iter().map(|x| {
// do some stuff, but not invoke Test::test() method, so I don't need type information
()
});
}

错误为:

error[E0277]: the trait bound `Bar: Test<i64>` is not satisfied
--> src/main.rs:24:57
|
24 |     let xs: Vec<Box<dyn Test<_>>> = vec![Box::new(Foo), Box::new(Bar)];
|                                                         ^^^^^^^^^^^^^ the trait `Test<i64>` is not implemented for `Bar`
|
= help: the following implementations were found:
<Bar as Test<std::string::String>>
= note: required for the cast to the object type `dyn Test<i64>`

我理解编译器为什么会给我这个错误:我把Foo放在第一位,它有i64作为类型参数。之后,编译器只期望i64作为类型参数。但是有办法解决这个问题吗?

我认为你不能让它完全像这样工作。

要获得类似的结果,您可以选择让元素实现另一个非通用特性,然后如果您事先不知道T的哪些类型最终是可能的,则将其添加到Vec中,即该特性是您的公共API的一部分,而其他板条箱则希望为其自己的类型T实现该特性。

trait NonGenericTest {}
trait Test2<T> : NonGenericTest {
fn test(&self) -> T;
}
impl NonGenericTest for Foo{}
impl NonGenericTest for Bar{}
impl Test2<i64> for Foo {
fn test(&self) -> i64 {
println!("foo");
42
}
}
impl Test2<String> for Bar {
fn test(&self) -> String {
println!("bar");
"".to_string()
}
}
fn main()  {
let xs: Vec<Box<dyn NonGenericTest>> = vec![Box::new(Foo), Box::new(Bar)];
xs.iter().map(|x| {
// do some stuff, but not invoke Test::test() method, so I don't need type information
()
});
}

或者,如果你提前知道T的所有可能类型,你可以将特征中的T更改为包含你想在这里支持的所有类型的枚举:

enum TestResult {
ResultI64(i64),
ResultString(String),
}
trait Test {
fn test(&self) -> TestResult;
}
struct Foo;
struct Bar;
impl Test for Foo {
fn test(&self) -> TestResult {
println!("foo");
TestResult::ResultI64(42)
}
}
impl Test for Bar {
fn test(&self) -> TestResult {
println!("bar");
TestResult::ResultString("".to_string())
}
}
fn main(){
let xs: Vec<Box<dyn Test>> = vec![Box::new(Foo), Box::new(Bar)];
xs.iter().map(|x| {
// do some stuff, but not invoke Test::test() method, so I don't need type information
()
});
}