在分离的mod中使用实现时,多个``impl''错误

发布于 2025-02-12 09:23:53 字数 5155 浏览 0 评论 0 原文

挖掘孤儿规则的主题,我最终得到了类型的实现”板条箱。但是结果,我现在还有另一个关于特征实现的问题。以下示例效果很好:

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", ]

与结果:

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

但是,如果我替换了主:

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(); }

获得以下错误:

--> 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;

为什么使用“使用c3 :: ...;”时,为什么会出现此错误。和“使用C4 :: ...;”在分离的mod中应用吗?

顺便说一句,以下情况非常有效(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(); }

带有结果:

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

因此,此行为有点奇怪:仅当C3 :: myt and c4 :: myt c3 :: myt均缺乏涡轮人的编译器,而没有涡轮。被使用,但这似乎是紫色的,因为它们用于分离的mod中。

附加组件:货物文件的详细定义:

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" }

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. 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::...;" and "use c4::...;" are applied within separated mods?

By the way, the following case works perfectly (unused_imports allowed only to avoid warnings):

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.

ADD-ON: Detailed definition of the cargo files:

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" }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

我最亲爱的 2025-02-19 09:23:53

这是因为您的特征是通用的,并且Rust没有真正的方法可以找出没有Turbofish的类型( ::&lt;&gt; )。在情况下,这似乎很明显,因为只有一个 impl ,但这并不是典型的,因为它实际上并不是一个通用的意义。

要亲自查看此内容,在 C3 中,您可以添加第二个 Impl block,现在很容易看到无法推断type type type parameter t t ,它很容易成为 myt i32

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"); }
}

然后,您可以指定任何一个类型 _3 :: f 来歧义函数呼叫:

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

我对为什么您的最后一个示例(“以下情况非常有效”)没有很好的解释同样的问题。

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 (::<>). 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.

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.

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:

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.

℡Ms空城旧梦 2025-02-19 09:23:53

如图所示: [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();
}

导致:

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

因此,在此问题的示例中不可能将MyTrait的两个实现用于同一板条箱C5中的Mytruct而不使用Turbofish。

Implementations seem ubiquitous through the entire crate as shown in example: [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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文