在Trait定义中使用impl Trait

Ame*_*meo 23 traits rust

是否可以将traits中的函数定义为具有impl Trait返回类型?我想创建一个可以由多个结构实现的特征,以便new()所有这些特征的函数返回一个对象,它们都可以以相同的方式使用,而无需编写特定于每个结构的代码.

trait A {
    fn new() -> impl A;
}
Run Code Online (Sandbox Code Playgroud)

但是,我收到以下错误:

impl Trait 不允许在函数和固有方法返回类型之外

这只是impl TraitRust 当前实现的限制还是我使用它错了?

She*_*ter 25

正如trentcl所提到的,你目前无法置于impl Trait特质方法的返回位置.

来自RFC 1522:

impl Trait只能在独立或固有impl函数的返回类型中编写,而不是在特征定义或任何非返回类型的位置.它们也可能不会出现在闭包特征或函数指针的返回类型中,除非它们本身是合法返回类型的一部分.

  • 最终,我们希望允许在特征中使用该特征[...]

现在,您必须使用盒装特征对象:

trait A {
    fn new() -> Box<dyn A>;
}
Run Code Online (Sandbox Code Playgroud)

也可以看看:

  • 再次感谢谢普大师。我没有完全考虑到这一点,所以我发现我的答案并没有直接解决这个问题。也就是说,它现在已被接受,并且似乎对OP有所帮助。我该如何继续?是否应该编辑该问题以删除“impl Trait”的具体使用,或者我们应该努力完全删除答案? (2认同)
  • @SimonWhitehead我不愿意如此彻底地编辑这个问题.我认为留下两个答案都没关系.你可以改变你的答案来说"虽然你不能做*X*但是,这是一个可能有帮助的解决方法".回答直接问题并提供有用的替代方案都是有价值的贡献.选中标记主要是"这个答案最有助于OP".投票意味着"这个答案对我有帮助". (2认同)

Sim*_*ead 10

如果您只需要返回当前正在实施特征的特定类型,您可能正在寻找Self.

trait A {
    fn new() -> Self;
}
Run Code Online (Sandbox Code Playgroud)

例如,这将编译:

trait A {
    fn new() -> Self;
}

struct Person;

impl A for Person {
    fn new() -> Person {
        Person
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,更完整的例子,展示使用特征:

trait A {
    fn new<S: Into<String>>(name: S) -> Self;
    fn get_name(&self) -> String;
}

struct Person {
    name: String
}

impl A for Person {
    fn new<S: Into<String>>(name: S) -> Person {
        Person { name: name.into() }
    }

    fn get_name(&self) -> String {
        self.name.clone()
    }
}

struct Pet {
    name: String
}

impl A for Pet {
    fn new<S: Into<String>>(name: S) -> Pet {
        Pet { name: name.into() }
    }

    fn get_name(&self) -> String {
        self.name.clone()
    }
}

fn main() {

    let person = Person::new("Simon");
    let pet = Pet::new("Buddy");

    println!("{}'s pets name is {}", get_name(&person), get_name(&pet));
}

fn get_name<T: A>(a: &T) -> String {
    a.get_name()
}
Run Code Online (Sandbox Code Playgroud)

操场

作为旁注..我在String这里使用赞成&str引用..减少对显式生命期的需要,并可能失去对手头问题的关注.我相信&str在借用内容时返回引用通常是惯例,这似乎是合适的.但是我不想过多地分散实际的例子.

  • 这与返回`impl Trait`不同.例如,你不能添加一个方法,在`Person`中返回一个`Pet`但在`Pet`中返回一个`Person`,尽管它们都实现了'A`.[RFC(1522)](https://github.com/rust-lang/rfcs/blob/master/text/1522-conservative-impl-trait.md)提到了这种限制,并表达了最终将其删除的愿望( "初始限制"下的第一颗子弹. (6认同)
  • 老实说,我没有考虑过@trentcl.我的回答似乎帮助了OP.鉴于它被接受,我该如何处理? (2认同)
  • @SimonWhitehead 我建议对第一句话进行编辑(不确定同行评审过程是如何工作的,也许你可以看到)。但我认为你的回答很好,没有理由不应该被接受(毕竟它解决了 OP 的直接问题)。 (2认同)

Jer*_*wen 6

通过显式命名返回类型,即使在不返回“ Self”的情况下,也可以获得类似的结果。

trait B {}
struct C;

impl B for C {}

trait A {
    type FReturn: B;
    fn f() -> Self::FReturn;
}

struct Person;

impl A for Person {
    type FReturn = C;
    fn f() -> C {
        C
    }
}
Run Code Online (Sandbox Code Playgroud)