如何在 Rust 中将变量设置为泛型 Trait 的实现?
How to set a variable to implementations of generic typed Trait in rust?
我是 Rust 的新手,我正在尝试编写一个应用程序,它基本上使用许多可能的服务之一来获取一些数据,然后 运行 对其进行格式化并保存到我的数据库中。
我正在尝试做一些类似于 Java 的通用接口,以根据命令行输入实例化正确的服务并在整个程序中使用它。
我编写了这样的代码:
use anyhow::Result;
pub trait Service<T> {
fn get_values(&self, id: u64) -> T;
fn convert_data(&self, input: T, output: &mut Vec<MyDataStruct>) -> Result<String>;
}
和两个不同的实现:
struct ServiceA {
clientA: DataRetrieverForA,
}
struct ServiceB {
clientB: DataRetrieverForB,
}
impl Service<Result<ADataStruct>> for ServiceA {
fn get_values(&self, id: u64) -> Result<ADataStruct>;
fn convert_data(&self, input: Result<ADataStruct>, output: &mut Vec<MyDataStruct>) -> Result<String>;
}
impl Service<BDataStruct> for ServiceB {
fn get_values(&self, id: u64) -> BDataStruct;
fn convert_data(&self, input: BDataStruct, output: &mut Vec<MyDataStruct>) -> Result<String>;
}
self.get_values(id)
使用 self.clientX
检索数据,self.convert_data(input, &mut output)
t运行 将数据从 ADataStruct
和 BDataStruct
转换为 MyDataStruct
在将其保存到我的数据库之前。
应用程序将 运行 使用 ServiceA
或 ServiceB
取决于命令行输入:
fn main() {
// ...
let service: Box<&(dyn Service<_>)> = match cli_service {
Service::A => { Box::new(&ServiceA::new(...) }
Service::B => { Box::new(&ServiceB::new(...) }
};
//...
}
我尝试了很多更改,主要基于 https://doc.rust-lang.org/book/ch10-02-traits.html and https://doc.rust-lang.org/book/ch17-02-trait-objects.html,但我找不到一个示例来处理使用特征定义中的泛型类型的函数。当我删除通用 参数并将其固定为一些通用结构以进行测试时,代码已编译并且 运行 没有错误。所以我猜我的错误是 generic/trait 用法。
我用这段代码得到的错误:
error[E0277]: the trait bound `ServiceB: Service<ADataStruct>` is not satisfied
--> ori-runner\src\main.rs:40:37
|
40 | ... { Box::new(&ServiceB::new(params)...
| -------- ^^^^^^^^^^^^^^^^^^^^^^ the trait `Service<ADataStruct>` is not implemented for `ServiceB`
| |
| required by a bound introduced by this call
|
= help: the following implementations were found:
<ServiceB as Service<BDataStructure>>
= note: required for the cast to the object type `dyn Service<ADataStruct>>`
我做错了什么?很明显,第一个匹配类型定义了 dyn 服务变量的“_”,但我没有想法,google 搜索...
谢谢!
由于类型不同,一种选择是将它们包装在 enum
中,并有一些 method/s 用于根据决策计算所需的任何内容。枚举包装器将抽象服务操作。
struct DataRetrieverForA {}
struct DataRetrieverForB {}
struct ADataStruct {}
struct BDataStruct {}
struct MyDataStruct {}
struct ServiceA {
clientA: DataRetrieverForA,
}
struct ServiceB {
clientB: DataRetrieverForB,
}
impl ServiceA {
fn get_values(&self, id: u64) -> Result<ADataStruct, ()> {
Ok(ADataStruct {})
}
fn convert_data(
&self,
input: Result<ADataStruct, ()>,
output: &mut Vec<MyDataStruct>,
) -> Result<String, ()> {
Ok("foo".into())
}
}
impl ServiceB {
fn get_values(&self, id: u64) -> BDataStruct {
BDataStruct {}
}
fn convert_data(
&self,
input: BDataStruct,
output: &mut Vec<MyDataStruct>,
) -> Result<String, ()> {
Ok("bar".into())
}
}
enum Services {
A(ServiceA),
B(ServiceB),
}
impl Services {
fn a() -> Self {
Self::A(ServiceA {
clientA: DataRetrieverForA {},
})
}
fn b() -> Self {
Self::B(ServiceB {
clientB: DataRetrieverForB {},
})
}
fn compute(self) {
todo!()
}
}
fn main() {
let arg = "a";
let service = match arg {
"a" => Services::a(),
_ => Services::b(),
};
service.compute();
}
我是 Rust 的新手,我正在尝试编写一个应用程序,它基本上使用许多可能的服务之一来获取一些数据,然后 运行 对其进行格式化并保存到我的数据库中。
我正在尝试做一些类似于 Java 的通用接口,以根据命令行输入实例化正确的服务并在整个程序中使用它。
我编写了这样的代码:
use anyhow::Result;
pub trait Service<T> {
fn get_values(&self, id: u64) -> T;
fn convert_data(&self, input: T, output: &mut Vec<MyDataStruct>) -> Result<String>;
}
和两个不同的实现:
struct ServiceA {
clientA: DataRetrieverForA,
}
struct ServiceB {
clientB: DataRetrieverForB,
}
impl Service<Result<ADataStruct>> for ServiceA {
fn get_values(&self, id: u64) -> Result<ADataStruct>;
fn convert_data(&self, input: Result<ADataStruct>, output: &mut Vec<MyDataStruct>) -> Result<String>;
}
impl Service<BDataStruct> for ServiceB {
fn get_values(&self, id: u64) -> BDataStruct;
fn convert_data(&self, input: BDataStruct, output: &mut Vec<MyDataStruct>) -> Result<String>;
}
self.get_values(id)
使用 self.clientX
检索数据,self.convert_data(input, &mut output)
t运行 将数据从 ADataStruct
和 BDataStruct
转换为 MyDataStruct
在将其保存到我的数据库之前。
应用程序将 运行 使用 ServiceA
或 ServiceB
取决于命令行输入:
fn main() {
// ...
let service: Box<&(dyn Service<_>)> = match cli_service {
Service::A => { Box::new(&ServiceA::new(...) }
Service::B => { Box::new(&ServiceB::new(...) }
};
//...
}
我尝试了很多更改,主要基于 https://doc.rust-lang.org/book/ch10-02-traits.html and https://doc.rust-lang.org/book/ch17-02-trait-objects.html,但我找不到一个示例来处理使用特征定义中的泛型类型的函数。当我删除通用 参数并将其固定为一些通用结构以进行测试时,代码已编译并且 运行 没有错误。所以我猜我的错误是 generic/trait 用法。
我用这段代码得到的错误:
error[E0277]: the trait bound `ServiceB: Service<ADataStruct>` is not satisfied
--> ori-runner\src\main.rs:40:37
|
40 | ... { Box::new(&ServiceB::new(params)...
| -------- ^^^^^^^^^^^^^^^^^^^^^^ the trait `Service<ADataStruct>` is not implemented for `ServiceB`
| |
| required by a bound introduced by this call
|
= help: the following implementations were found:
<ServiceB as Service<BDataStructure>>
= note: required for the cast to the object type `dyn Service<ADataStruct>>`
我做错了什么?很明显,第一个匹配类型定义了 dyn 服务变量的“_”,但我没有想法,google 搜索...
谢谢!
由于类型不同,一种选择是将它们包装在 enum
中,并有一些 method/s 用于根据决策计算所需的任何内容。枚举包装器将抽象服务操作。
struct DataRetrieverForA {}
struct DataRetrieverForB {}
struct ADataStruct {}
struct BDataStruct {}
struct MyDataStruct {}
struct ServiceA {
clientA: DataRetrieverForA,
}
struct ServiceB {
clientB: DataRetrieverForB,
}
impl ServiceA {
fn get_values(&self, id: u64) -> Result<ADataStruct, ()> {
Ok(ADataStruct {})
}
fn convert_data(
&self,
input: Result<ADataStruct, ()>,
output: &mut Vec<MyDataStruct>,
) -> Result<String, ()> {
Ok("foo".into())
}
}
impl ServiceB {
fn get_values(&self, id: u64) -> BDataStruct {
BDataStruct {}
}
fn convert_data(
&self,
input: BDataStruct,
output: &mut Vec<MyDataStruct>,
) -> Result<String, ()> {
Ok("bar".into())
}
}
enum Services {
A(ServiceA),
B(ServiceB),
}
impl Services {
fn a() -> Self {
Self::A(ServiceA {
clientA: DataRetrieverForA {},
})
}
fn b() -> Self {
Self::B(ServiceB {
clientB: DataRetrieverForB {},
})
}
fn compute(self) {
todo!()
}
}
fn main() {
let arg = "a";
let service = match arg {
"a" => Services::a(),
_ => Services::b(),
};
service.compute();
}