简体   繁体   English

在 rust 中将特征与关联类型组合

[英]Combine traits with associated types in rust

I'm trying to create a kind of wrapper trait that combines multiples traits and a function that return the associated implementation of the trait.我正在尝试创建一种包装器特征,它结合了多个特征和一个 function 返回特征的相关实现。 It works well as long as you don't have associated types.只要您没有关联类型,它就可以正常工作。 I don't know how to refer to the Output type I am aware of how to combine traits: Is there a way to combine multiple traits in order to define a new trait?我不知道如何引用Output类型我知道如何组合特征: 有没有办法组合多个特征以定义新特征? Is there any way to create a type alias for multiple traits? 有没有办法为多个特征创建类型别名?

But unfortunately, I've not found anything with associated types但不幸的是,我没有发现任何关联类型

Here is a summarized example of where I'm stucked这是我被困在哪里的总结示例

use std::ops::Add;

pub trait Hello {
    fn hello(&self);
}
pub trait Goodbye {
    fn goodbye(&self);
}
struct Suffix {
    suffix: String,
}
pub struct World {
    content: String,
}

impl World {
    fn new(content: String) -> Self {
        World { content: content }
    }
}

impl Hello for World {
    fn hello(&self) {
        println!("Hello {}", self.content)
    }
}
impl Goodbye for World {
    fn goodbye(&self) {
        println!("Goodbye {}", self.content)
    }
}
impl Add<Suffix> for World {
    type Output = World;
    fn add(self, other: Suffix) -> World {
        let suffixed: String = self.content + &other.suffix;
        World::new(suffixed)
    }
}

trait HelloGoodbye: Hello + Goodbye {}
impl<T> HelloGoodbye for T where T: Hello + Goodbye {}

fn get_hello_goodbye() -> Box<dyn HelloGoodbye> {
    Box::new(World::new("Everyone".to_string()))
}

trait SuffixableHello: Hello + Add<Suffix, Output = Self> {}
impl<T> SuffixableHello for T where T: Hello + Add<Suffix, Output = Self> {}

fn get_suffixable_hello() -> Box<dyn SuffixableHello> {
    Box::new(World::new("Everyone".to_string()))
}


fn main() {
    // This works
    let hello_goodbye = get_hello_goodbye();
    hello_goodbye.hello();
    hello_goodbye.goodbye();

    // This does not work
    let suffixable_hello = get_suffixable_hello();
    suffixable_hello.hello()
}

I got this compilation error:我收到此编译错误:

49 | fn get_suffixable_hello() -> Box<dyn SuffixableHello> {
   |                                      ^^^^^^^^^^^^^^^ help: specify the associated type: `SuffixableHello<Output = Type>`

What am I supposed to put there?我应该把什么放在那里?

What I've try so far:到目前为止我尝试了什么:

  • Make trait generic使特征通用
trait SuffixableHello<T>: Hello + Add<Suffix, Output = T> {}
impl<T, U> SuffixableHello<T> for T where T: Hello + Add<Suffix, Output = Self> {}

And I get我得到

   |
49 | fn get_suffixable_hello() -> Box<dyn SuffixableHello<T>> {
   |                                      ~~~~~~~~~~~~~~~~~~

Where am I supposed to add this T generic?我应该在哪里添加这个T泛型? Does my fucntion need to be generic?我的功能需要通用吗?

  • Only add Output to implementation只在实现中添加 Output
trait SuffixableHello: Hello + Add<Suffix> {}
impl<T> SuffixableHello for T where T: Hello + Add<Suffix, Output = T> {}

But I get:但我得到:

the value of the associated type `Output` (from trait `Add`) must be specified

This makes sense since Output is not declared in the trait.这是有道理的,因为 Output 没有在特征中声明。

  • Replacing World by Self in the impl Add<Suffix> for Worldimpl Add<Suffix> for World中用Self替换World

Am I missing something here?我在这里错过了什么吗? Thank you谢谢

Also, what if we want to return from the get_suffixable_hello() one of two Hello implementations, let's say World and World2 to cite @cadolphs like in this doc https://doc.rust-lang.org/rust-by-example/trait/dyn.html此外,如果我们想从两个Hello实现之一的get_suffixable_hello()返回怎么办,假设WorldWorld2引用 @cadolphs 就像在这个文档https://doc.rust-lang.org/rust-by-example/特征/动态.html

fn get_suffixable_hello() -> Box<dyn SuffixableHello<Output=World>> {
    Box::new(World::new("Everyone".to_string()))
}

does the trick.做的伎俩。

EDIT: Longer explanation.编辑:更长的解释。 Your first initial compiler error tells you that you can't just return Box<dyn SuffixableHello> .您的第一个初始编译器错误告诉您不能只返回Box<dyn SuffixableHello> That's because having the same trait but with different associated types isn't allowed, because the signatures of associated methods would be different.这是因为不允许具有相同的特征但具有不同的关联类型,因为关联方法的签名会不同。

So.所以。 We need to put a type there.我们需要在那里放一个类型。 And what should that type be?那种类型应该是什么? Well, given that you're explicitly calling World::new , there's really only one type that makes sense here, and that's World .好吧,鉴于您显式调用World::new ,这里实际上只有一种类型有意义,那就是World

In your toy example that makes it of course a bit silly and redundant because there's only one struct that implements all those traits.在您的玩具示例中,这当然有点愚蠢和多余,因为只有一个结构可以实现所有这些特征。

If you had another struct, World2 , you could not have it be returned by get_suffixable_hello next to World , because World2 would have associated type Output=World2 and hence wouldn't match the Output=World associated type.如果您有另一个结构World2 ,则无法通过World旁边的get_suffixable_hello返回它,因为World2将具有关联类型Output=World2 ,因此不会匹配Output=World关联类型。

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM