提问人:Alberto 提问时间:11/9/2023 更新时间:11/11/2023 访问量:81
具有默认特征实现的 Rust 泛型
Rust Generics with Default Trait Implementations
问:
我正在做一个 Rust 项目,我定义了几个特征(A1、A2 和 A3),每个特征都有多个实现。我还有一个结构算法,它基于这些特征采用泛型。我想为泛型提供默认特征实现,以防用户未提供特定实现。
这是我的代码:
pub trait A1 {
fn test1();
}
#[derive(Default)]
pub struct Ex1_A1;
impl A1 for Ex1_A1 {
fn test1() {
println!("Ex1_A1");
}
}
pub struct Ex2_A1;
impl A1 for Ex2_A1 {
fn test1() {
println!("Ex2_A1");
}
}
pub trait A2 {
fn test2();
}
pub struct Ex1_A2;
impl A2 for Ex1_A2 {
fn test2() {
println!("Ex1_A2");
}
}
pub trait A3 {
fn test3();
}
pub struct Ex1_A3;
impl A3 for Ex1_A3 {
fn test3() {
println!("Ex1_A3");
}
}
struct Algo<B: A1, S: A2, M: A3> {
a1: B,
a2: S,
a3: M
}
impl <B: A1, S: A2, M: A3> Algo<B, S, M> {
pub fn new(bbs: Option<B>, su: Option<S>, mac: Option<M>) -> Self {
let bbs = bbs.unwrap_or(Ex1_A1);
let su = su.unwrap_or(Ex1_A2);
let mac = mac.unwrap_or(Ex1_A3);
Self {
a1: bbs,
a2: su,
a3: mac,
}
}
}
我的问题是,如何为 Algo 结构中的泛型 B、S 和 M 提供默认实现?我尝试使用 Option 和 unwrap_or,但它似乎没有按预期工作。
我将不胜感激任何关于如何在 Rust 中有效处理这种情况的指导或示例。
谢谢!
答:
-1赞
Chayim Friedman
11/9/2023
#1
编译时值(泛型参数的类型)不能依赖于运行时值 ()。所以你不能那样做。Option
评论
0赞
Alberto
11/9/2023
那么,我怎样才能实现类似的东西呢?
0赞
Chayim Friedman
11/10/2023
@Alberto 每个默认值都可以有一个方法。或者你可以放弃你的想法,要求你的用户指定默认值。还不错。
0赞
user4815162342
11/9/2023
#2
提供默认值不能很好地与静态调度相吻合,因为泛型实现和默认实现的类型不同,因此无法使用明确的类型初始化字段。Algo
解决此问题的直接方法是使用 键入擦除字段。尽管动态调度由于它引入了间接性而有不好的说唱,但当用作算法的网关时,它确实非常好。例如,您可以这样定义:Algo
dyn ...
Algo
struct Algo {
a1: Box<dyn A1>,
a2: Box<dyn A2>,
a3: Box<dyn A3>,
}
impl Algo {
pub fn new(
bbs: Option<Box<dyn A1>>,
su: Option<Box<dyn A2>>,
mac: Option<Box<dyn A3>>,
) -> Self {
Self {
a1: bbs.unwrap_or_else(|| Box::new(Ex1_A1)),
a2: su.unwrap_or_else(|| Box::new(Ex1_A2)),
a3: mac.unwrap_or_else(|| Box::new(Ex1_A3)),
}
}
}
为此,您的特征方法需要采取:&self
pub trait A1 {
fn test1(&self);
}
#[derive(Default)]
pub struct Ex1_A1;
impl A1 for Ex1_A1 {
fn test1(&self) {
println!("Ex1_A1");
}
}
// ...
最后,现在使用 trait 对象调用:new()
fn main() {
let algo2 = Algo::new(Some(Box::new(Ex1_A1)), None, None);
}
评论
0赞
Alberto
11/9/2023
抱歉,这现在正在工作,当我尝试使用 new(None, None, None) 创建 Algo 实例时,它说需要类型注释
0赞
user4815162342
11/10/2023
@Alberto更新了答案,请看一下。
0赞
Alberto
11/10/2023
谢谢,你能帮我再走一步吗?我希望有另一个这样的结构: #[derive(Serialize, Deserialize)] struct Principal { //...其他属性 #[serde(skip_serializing)] alg: Algo } 但它是这样说的:“不满足绑定的特征”Algo: Deserialize<'_>
0赞
user4815162342
11/18/2023
@Alberto 我的回答对您的问题有帮助吗?如果是这样,请考虑接受它。
-1赞
Dmitry
11/9/2023
#3
首先,您需要将特征边界添加到:Default
impl
impl<B, S, M> Algo<B, S, M>
where
B: A1 + Default,
S: A2 + Default,
M: A3 + Default
{
pub fn new(bbs: Option<B>, su: Option<S>, mac: Option<M>) -> Self {
let bbs = bbs.unwrap_or_default();
let su = su.unwrap_or_default();
let mac = mac.unwrap_or_default();
Self {
a1: bbs,
a2: su,
a3: mac,
}
}
}
提高代码可用性的下一步是为泛型设置默认的具体类型:Algo
struct Algo<B: A1 = Ex1_A1, S: A2 = Ex1_A2, M: A3 = Ex1_A3> {
a1: B,
a2: S,
a3: M
}
// Now `Algo` without explicit generics definition means just `Algo<Ex1_A1, Ex1_A2, Ex1_A3>`
最后,在这里使用构建器模式要好得多:
impl Algo {
// Actually you can simply derive `Default` for the `Algo` instead of explicitly defining `new` method
// Writing this only for better understanding
pub fn new() -> Self
{
Self {
a1: Default::default(),
a2: Ex1_A2,
a3: Ex1_A3,
}
}
}
impl<B, S, M> Algo<B, S, M>
where
B: A1,
S: A2,
M: A3,
{
pub fn with_a1<NEW_B: A1>(self, a1: NEW_B) -> Algo<NEW_B, S, M> {
let Algo { a2, a3, .. } = self;
Algo { a1, a2, a3 }
}
pub fn with_a2<NEW_S: A2>(self, a2: NEW_S) -> Algo<B, NEW_S, M> {
let Algo { a1, a3, .. } = self;
Algo { a1, a2, a3 }
}
pub fn with_a3<NEW_M: A3>(self, a3: NEW_M) -> Algo<B, S, NEW_M> {
let Algo { a1, a2, .. } = self;
Algo { a1, a2, a3 }
}
}
现在,您可以根据需要管理您的构造:Algo
let my_algo = Algo::new()
.with_a1(Ex2_A1)
.with_a3(Ex1_A3);
评论
0赞
Alberto
11/9/2023
对不起,但这现在正在工作,编译器说“需要类型注释”
0赞
Dmitry
11/11/2023
添加了一些调整。工作正常 play.rust-lang.org/...
0赞
user4815162342
11/11/2023
我认为这实现了与 OP 需要的东西不同的东西。您的第一个代码片段需要实现的特征,并且还需要实现 - 但这不是 OP 想要的,他们希望在选项为 None 时使用不同的实现,而不是使用实现类型的默认配置。你的构建器模式也不起作用,因为 returns ,所以你唯一可以调用的是 。A1
A2
A3
Default
Algo::new()
Algo<Ex1_A1, Ex1_A2, Ex1_A3>
with_a1()
Ex2_A1
0赞
Dmitry
11/12/2023
“当选项为”无时,不同的实现“是什么意思?
评论