为什么不能在 rust 中实现 impl Trait 类型

问题描述 投票:0回答:1

说我有以下特质:

trait SayHello {
    fn say_hello(self) -> String;
}

为什么我可以这样做:

fn say_hello_twice(this: impl SayHello) -> String {
    let said_hello = this.say_hello();
    said_hello + " " + &said_hello
}

但不是这个:

impl impl SayHello {
    fn say_hello_twice(self) -> String {
        let said_hello = self.say_hello();
        said_hello + " " + &said_hello
    }
}

当后者看似只是前者的语法糖时?

rust traits
1个回答
0
投票

impl Trait
不是类型:从语义上讲,它的意思是“碰巧实现
Trait
的某种具体类型”。 在参数位置,就像在原来的
say_hello_twice
函数中一样,它只是泛型的语法糖 - 脱糖后的等价物如下:

fn say_hello_twice<T: SayHello>(this: T) -> String { ... }

它在 Rust 中是不允许的,所以它实际上没有任何定义的含义,但是使用

impl Trait
作为实现块的名义类型可能会有什么意图? 类比上面,或许是这样的:

impl<T: SayHello> T { ... }

但是,这也是不允许的:这样的实现将适用于实现

SayHello
的所有类型:包括在下游 crate 中定义的任何类型,并且固有实现只能在与类型本身相同的 crate 中定义,以防止名称冲突/歧义。

如果您想定义一个可用于

SayHello
的所有实现的方法,您有几种选择:

  1. SayHello
    特征中定义它,并使用默认实现:

    trait SayHello {
        fn say_hello(self) -> String;
        fn say_hello_twice(self) -> String {
            let said_hello = self.say_hello();
            said_hello.clone() + " " + &said_hello
        }
    }
    

    这有一个优点,那就是它只是

    SayHello
    上常见的、现成的方法。 然而,实现者可以选择覆盖定义——这可能是理想的,也可能是不理想的。

  2. 定义一个全面实现的扩展特征:

    trait SayHelloTwice {
        fn say_hello_twice(self) -> String;
    }
    
    impl<T: SayHello> SayHelloTwice for T {
        fn say_hello_twice(self) -> String {
            let said_hello = self.say_hello();
            said_hello.clone() + " " + &said_hello
        }
    }
    

    这样做的优点是

    SayHello
    的实现不能提供
    SayHelloTwice::say_hello_twice
    的任何其他定义。 但是,用户必须将
    SayHelloTwice
    纳入范围内,这稍微不太符合人体工程学。

  3. 可以使用

    dyn Trait
    作为固有实现块的标称类型:

    impl dyn SayHello {
        fn say_hello_twice(&self) -> String {
            let said_hello = self.say_hello_borrowed();
            said_hello.clone() + " " + &said_hello
        }
    }
    

    但是,用户必须使用特征对象(

    &dyn SayHello
    Box<dyn SayHello>
    等),这涉及运行时间接,可能不是您想要的;此外,由于
    dyn Trait
    未调整大小,因此您无法按值获取
    self
    (因此使用上面的
    &self
    say_hello_borrowed
    )。

© www.soinside.com 2019 - 2024. All rights reserved.