Rust 有可能拥有一个动态的通用特征集合吗?
我有一个带有泛型类型参数的特性。我想把实现这个特性的不同对象放在一个集合中。对象具有不同的类型参数 当我这样做时,编译器告诉我需要指定泛型类型参数。实际上,我的案例不需要这个泛型类型信息,所以某种通配符对我来说是可行的。让我展示代码,因为它更好地显示了我的意图:Rust 有可能拥有一个动态的通用特征集合吗?,rust,Rust,我有一个带有泛型类型参数的特性。我想把实现这个特性的不同对象放在一个集合中。对象具有不同的类型参数 当我这样做时,编译器告诉我需要指定泛型类型参数。实际上,我的案例不需要这个泛型类型信息,所以某种通配符对我来说是可行的。让我展示代码,因为它更好地显示了我的意图: trait Test<T> { fn test(&self) -> T; } struct Foo; struct Bar; impl Test<i64> for Foo { fn
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实现它
我想你不能让它完全像这样工作 实现类似结果的选项是:要么让元素实现另一个非通用特性,如果您事先不知道T的最终可能类型,则将其添加到Vec中,即该特性是公共API的一部分,其他板条箱预计将为其自己的类型T实现它
如果你的部分特质本身在没有T的情况下是有用的,那么就做两个特质。当Foo同时实现Test和Test时,那么哪一个应该框起来作为Box使用?如果你的部分特质本身在没有T的情况下是有用的,那么就做两个特质。当Foo同时实现Test和Test时,那么哪一个应该框起来作为Box使用?还有第三个选项,形成子特征形成子特征,如在这种情况下。不是最漂亮的代码,因为到处都是PhantomData,但它很有效。这对我来说似乎很有用,但我不确定为什么需要PhantomData或者它的作用。PhantomData是区分Foo as Test和Foo as Test所必需的,当Foo同时实现这两个特性时。如果您尝试为T编写:impl Test2,它将失败,并出现一个错误,表明U是无约束的。还有第三个选项,可以生成一个子特性,如下面所示。不是最漂亮的代码,因为到处都是PhantomData,但它很有效。这对我来说似乎很有用,但我不确定为什么需要PhantomData或者它的作用。PhantomData是区分Foo as Test和Foo as Test所必需的,当Foo同时实现这两个函数时,如果您尝试为T编写:impl Test2,它将失败,并出现一个错误,表明U是无约束的。
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
()
});
}
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
()
});
}