Rust中Arc<dyn Trait>满足Borrow<_>多实现冲突的解决问询
问题:Borrow trait 多实现导致的类型推断错误及解决方法
问题背景
我定义了这样的函数签名:
pub fn execute<DS: Borrow<impl DataSet + ?Sized>> ( data: DS)
其中DataSet是自定义Trait,我希望通过Borrow支持传入Arc<dyn DataSet>或&impl DataSet作为参数,但编译时报错:
error[E0283]: type annotations needed --> driver\src\api\mod.rs:127:13 | 127 | base_engine::execute_aggregation( | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `impl DataSet + ?Sized` declared on the function `execute_aggregation` | = note: multiple `impl`s satisfying `Arc<dyn DataSet>: Borrow<_>` found in the following crates: `alloc`, `core`: - impl<T> Borrow<T> for Arc<T> where T: ?Sized; - impl<T> Borrow<T> for T where T: ?Sized; note: required by a bound in `execute_aggregation` --> c:\rust\ultima\base_engine\src\api\execute_agg.rs:15:32 | 15 | pub fn execute_aggregation<DS: Borrow<impl DataSet + ?Sized>> ( | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `execute_aggregation`
最小复现代码:
use std::{sync::Arc, borrow::Borrow}; pub fn test () { let tt = St{name: "Anatoly".into()}; let att = Arc::new(tt); ppr(att); } fn ppr<T: Borrow<impl Namable>> (s: T) { let name = s.borrow(); let n = name.my_name(); println!("{}", n) } struct St { name: String } trait Namable { fn my_name(&self) -> &String; } impl Namable for St { fn my_name(&self) -> &String { &self.name } }
原因分析
问题出在函数签名里的Borrow<impl DataSet + ?Sized>写法上——这里的impl Trait是存在类型,编译器需要确定具体是哪个类型满足约束,但对于Arc<dyn DataSet>来说,有两个合法的Borrow实现:
Arc<T>实现了Borrow<T>(此处T是dyn DataSet),所以Arc<dyn DataSet>可以Borrow<dyn DataSet>;- 所有类型都实现了
Borrow<Self>,所以Arc<dyn DataSet>也可以Borrow<Arc<dyn DataSet>>,而Arc<dyn DataSet>本身也实现了DataSettrait。
这两个实现都符合Borrow<impl DataSet + ?Sized>的约束,编译器无法判断你到底想用哪一个,因此抛出类型推断错误。
解决方法
把函数签名里的存在类型改成泛型参数,明确约束Borrow的目标类型必须实现DataSet:
修正后的函数签名
pub fn execute<DS, D>(data: DS) where DS: Borrow<D>, D: DataSet + ?Sized,
对应最小复现代码里的ppr函数,修正后:
fn ppr<T, N>(s: T) where T: Borrow<N>, N: Namable + ?Sized, { let name = s.borrow(); let n = name.my_name(); println!("{}", n) }
这样编译器就能明确:我们需要T能够借用一个实现了Namable(或DataSet)的类型N,而非模糊的存在类型,也就不会出现多实现冲突的问题了。
另外,如果你只想接受能直接借用dyn DataSet的类型,也可以直接写DS: Borrow<dyn DataSet>,但泛型参数的写法更灵活,能同时支持具体类型和trait对象的借用。
内容的提问来源于stack exchange,提问作者Anatoly Bugakov
相关产品推荐
相关产品推荐

