简体   繁体   English

在单独的 mod 中使用实现时出现多个 impl 错误

[英]Multiple `impl`s error while use-ing implementations within separated mods

Digging into the subject of the orphan rule, I ended up with a kind of implementation of a trait by a type both defined outside the implementing crate.深入研究孤儿规则的主题,我最终得到了一种通过在实现板条箱之外定义的类型的特征实现。 But as a result, I now have another question about trait implementation.但结果,我现在有另一个关于 trait 实现的问题。 The following example works well:以下示例运行良好:

orphan/ | c1/ | src/lib.rs | pub trait MyTrait<T> {
        |     |            |    fn my_task(&self);
        |     |            | }
        |     |
        |     | Cargo.toml -> DEFINITION BELOW
        |
        | c2/ | src/lib.rs | pub struct MyStruct;
        |     |
        |     | Cargo.toml -> DEFINITION BELOW
        |
        | c3/ | src/lib.rs | use c1::MyTrait; use c2::MyStruct;
        |     |            | pub enum MyT {}
        |     |            | impl MyTrait<MyT> for MyStruct {
        |     |            |    fn my_task(&self) { println!("This is c3 implementation"); }
        |     |            | }
        |     |
        |     | Cargo.toml -> DEFINITION BELOW
        |
        | c4/ | src/lib.rs | use c1::MyTrait; use c2::MyStruct;
        |     |            | pub enum MyT {}
        |     |            | impl MyTrait<MyT> for MyStruct {
        |     |            |    fn my_task(&self) { println!("This is c4 implementation"); }
        |     |            | }
        |     |
        |     | Cargo.toml -> DEFINITION BELOW
        |
        | c5/ | src/main.rs | mod _3 {
        |     |             |     use c1::*; use c2::*; use c3::*;
        |     |             |     pub fn f() { MyTrait::<MyT>::my_task(&MyStruct); }
        |     |             | }
        |     |             | mod _4 {
        |     |             |     use c1::*; use c2::*; use c4::*;
        |     |             |     pub fn f() { MyTrait::<MyT>::my_task(&MyStruct); }
        |     |             | }
        |     |             | fn main() { _3::f(); _4::f(); }
        |     |
        |     | Cargo.toml -> DEFINITION BELOW
        |
        | Cargo.toml | [workspace]
                     | members = [ "c1", "c2", "c3", "c4", "c5", ]

with result:结果:

cargo run --release
   Compiling c5 v0.0.1 (XXX\orphan\c5)
    Finished release [optimized] target(s) in 0.27s
     Running `target\release\c5.exe`
This is c3 implementation
This is c4 implementation

But if I replace the main by:但是,如果我将主要替换为:

main.rs | mod _3 {
        |    use c1::*; use c2::*; use c3::*;
        |    pub fn f() { MyTrait::my_task(&MyStruct); }
        | }
        | mod _4 {
        |     use c1::*; use c2::*; use c4::*;
        |     pub fn f() { MyTrait::<MyT>::my_task(&MyStruct); }
        | }
        | fn main() { _3::f(); _4::f(); }

the following error is obtained:得到以下错误:

--> c5\src\main.rs:3:18
  |
3 |     pub fn f() { MyTrait::my_task(&MyStruct); }
  |                  ^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the trait `MyTrait`
  |
  = note: multiple `impl`s satisfying `c2::MyStruct: c1::MyTrait<_>` found in the following crates: `c3`, `c4`:
          - impl c1::MyTrait<c3::MyT> for c2::MyStruct;
          - impl c1::MyTrait<c4::MyT> for c2::MyStruct;

Why such error, while "use c3::...;"为什么会出现这样的错误,而“使用 c3::...;” and "use c4::...;"和“使用 c4::...;” are applied within separated mods?在单独的模组中应用?

By the way, the following case works perfectly (unused_imports allowed only to avoid warnings):顺便说一句,以下情况非常有效(只允许使用 unused_imports 以避免警告):

main.rs | mod _3 {
        |    use c1::*; use c2::*; #[allow(unused_imports)] use c3::*;
        |    pub fn f() { MyTrait::my_task(&MyStruct); }
        | }
        | fn main() { _3::f(); }

with result:结果:

cargo run --release
   Compiling c5 v0.0.1 (XXX\orphan\c5)
    Finished release [optimized] target(s) in 0.28s
     Running `target\release\c5.exe`
This is c3 implementation

This behavior is thus a little bit strange : the compiler desagrees with the absence of turbofish only when both c3::MyT and c4::MyT are used, but that seems unlogic because they are used in separated mods.因此,这种行为有点奇怪:编译器仅在同时使用 c3::MyT 和 c4::MyT 时才不同意缺少 turbofish,但这似乎不合逻辑,因为它们在单独的 mod 中使用。

ADD-ON: Detailed definition of the cargo files: ADD-ON:货物文件的详细定义:

c1/Cargo.toml | [package]
              | name = "c1"
              | version = "0.0.1"
              | edition = "2021"
              | [dependencies]

c2/Cargo.toml | [package]
              | name = "c2"
              | version = "0.0.1"
              | edition = "2021"
              | [dependencies]

c3/Cargo.toml | [package]
              | name = "c3"
              | version = "0.0.1"
              | edition = "2021"
              | [dependencies]
              | c1 = { path = "../c1", version = "0.0.1" }
              | c2 = { path = "../c2", version = "0.0.1" }
        
c4/Cargo.toml | [package]
              | name = "c4"
              | version = "0.0.1"
              | edition = "2021"
              | [dependencies]
              | c1 = { path = "../c1", version = "0.0.1" }
              | c2 = { path = "../c2", version = "0.0.1" }
        
c5/Cargo.toml | [package]
              | name = "c5"
              | version = "0.0.1"
              | edition = "2021"
              | [dependencies]
              | c1 = { path = "../c1", version = "0.0.1" }
              | c2 = { path = "../c2", version = "0.0.1" }
              | c3 = { path = "../c3", version = "0.0.1" }
              | c4 = { path = "../c4", version = "0.0.1" }

It is because your trait is generic, and there is no real way for Rust to figure out which type it should be without the turbofish ( ::<> ).这是因为您的 trait 是通用的,Rust 没有真正的方法来确定没有涡轮鱼( ::<> )它应该是哪种类型。 In this case, it seems obvious because there is only one impl , but that's not typical, because then there isn't really a point of it being generic.这种情况下,这似乎很明显,因为只有一个impl ,但这并不典型,因为这样就没有真正意义上的通用性。

To see this yourself, in c3 , you can add a second impl block, and now it is pretty easy to see what it means by cannot infer type parameter T , it could just as easily be MyT or i32 .要自己查看,在c3中,您可以添加第二个impl块,现在很容易看出cannot infer type parameter T的含义,它可以很容易地是MyTi32

impl MyTrait<MyT> for MyStruct {
    fn my_task(&self) { println!("This is c3 implementation"); }
}
impl MyTrait<i32> for MyStruct {
    fn my_task(&self) { println!("This is c3 implementation for i32"); }
}

You can then specify either type in _3::f to disambiguate the function call:然后,您可以在_3::f中指定任一类型以消除函数调用的歧义:

MyTrait::<MyT>::my_task(&MyStruct);
MyTrait::<i32>::my_task(&MyStruct);

I don't have a good explanation on why your last example ("the following case works perfectly") doesn't experience the same issues though.我没有很好的解释为什么你的最后一个例子(“以下案例完美地工作”)没有遇到同样的问题。

Implementations seem ubiquitous through the entire crate as shown in example: [playground]实现似乎在整个 crate 中无处不在,如示例所示: [playground]

trait Trait {
    fn my_fn();
}

enum Enum {}

mod _nothing_mod {
    struct _Nothing;
    impl _Nothing {
        fn _do_nothing() {
            use crate::{ Enum, Trait, };
            impl Trait for Enum {
                fn my_fn() { 
                    impl Enum {
                        pub fn new() -> Option<Self> {
                            println!("cannot create Enum instance");
                            None
                        }
                    }
                    println!("a task") 
                }
            }
        }
    }
}

fn main() {
    Enum::new();
    Enum::my_fn();
}

resulting in:导致:

Standard Error

   Compiling playground v0.0.1 (/playground)
    Finished dev [unoptimized + debuginfo] target(s) in 0.60s
     Running `target/debug/playground`

Standard Output

cannot create Enum instance
a task

For this reason, it is not possible in the example of this question to use the two implementations of MyTrait for MyStruct in same crate c5 without using the turbofish.出于这个原因,在这个问题的示例中,如果不使用 turbofish,就不可能在同一个 crate c5 中为 MyStruct 使用 MyTrait 的两个实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在Rust中派生实例时的多个impl候选 - Multiple impl candidate while deriving an instance in Rust 是否可以在 trait 定义中使用 `impl Trait` 作为函数的返回类型? - Is it possible to use `impl Trait` as a function's return type in a trait definition? ndarray - 尝试使用 impl AddAssign<arraybase> 对于 ArrayBase 导致编译器错误</arraybase> - ndarray - Trying to use impl AddAssign<ArrayBase> for ArrayBase causes compiler error 如何使用来自其他 mod 的 Rust 结构 - How to use Rust structs from other mods 使用 `cfg!` 宏在多个实现之间进行选择的正确方法是什么? - What is the proper way to use the `cfg!` macro to choose between multiple implementations? 在 trait impl 中理解自我 - Understanding Self within a trait impl 在另一个结构的 impl 中,如何从用户输入中获取输入以分配结构的值? - How do you get input to assign the values of structs from user input while in another struct's impl? 多个 `impl` 满足 `Arc<dyn ds> : Borrow<_>` 在以下板条箱中找到:`alloc`, `core`</dyn> - Multiple `impl`s satisfying `Arc<dyn DS>: Borrow<_>` found in the following crates: `alloc`, `core` 在 Rust 的其他文件中导入 mod 的正确方法是什么? - What's the proper way to import mods in other files in Rust? 用于多个错误处理的impl trait - impl trait for multiple errors handling
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM