是否可以在特征定义中将`impl Trait`用作函数的返回类型?

问题描述 投票:22回答:4

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

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

但是,出现以下错误:

error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
 --> src/lib.rs:2:17
  |
2 |     fn new() -> impl A;
  |                 ^^^^^^

这是对impl Trait当前实现的限制,还是我使用错了?

rust traits
4个回答
9
投票

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

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

例如,它将编译:

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

struct Person;

impl A for Person {
    fn new() -> Person {
        Person
    }
}

或更完整的示例,使用特征进行演示:

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

Playground

作为附带说明。我在这里使用String来代替&str参考。.减少了对明确寿命的需求,并减少了对当前问题的关注。我认为,借用内容时通常会返回一个&str引用,这似乎很合适。但是我不想过多地偏离实际示例。


24
投票

作为trentcl mentions,当前不能将impl Trait置于特征方法的返回位置。

来自RFC 1522

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

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

现在,您必须使用一个装箱的特征对象:

trait A {
    fn new() -> Box<dyn A>;
}

另请参见:

如果您希望使用不稳定的夜间功能,可以使用existential types (RFC 2071)

// 1.40.0-nightly (2019-11-05 1423bec54cf2db283b61)
#![feature(type_alias_impl_trait)]

trait FromTheFuture {
    type Iter: Iterator<Item = u8>;

    fn example(&self) -> Self::Iter;
}

impl FromTheFuture for u8 {
    type Iter = impl Iterator<Item = u8>;

    fn example(&self) -> Self::Iter {
        std::iter::repeat(*self).take(*self as usize)
    }
}

fn main() {
    for v in 7.example() {
        println!("{}", v);
    }
}

6
投票

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


0
投票

Rust还不熟悉,所以可能需要检查。

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