Rust 是否可以使用'impl Trait'作为函数';特征定义中的返回类型是什么?

Rust 是否可以使用'impl Trait'作为函数';特征定义中的返回类型是什么?,rust,traits,Rust,Traits,有没有可能将Trait中的函数定义为具有impl Trait返回类型?我想创建一个可以由多个结构实现的trait,这样所有结构的new()函数都会返回一个对象,它们都可以以相同的方式使用,而不必编写特定于每个结构的代码 trait A { fn new() -> impl A; } 但是,我得到以下错误: 错误[E0562]:`impl Trait`不允许在函数和固有方法返回类型之外 -->src/lib.rs:2:17 | 2 | fn new()->impl A; |

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

trait A {
    fn new() -> impl A;
}
但是,我得到以下错误:

错误[E0562]:`impl Trait`不允许在函数和固有方法返回类型之外
-->src/lib.rs:2:17
|
2 | fn new()->impl A;
|                 ^^^^^^

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

如果您只需要返回当前为其实现Trait的特定类型,您可能正在查找
Self

trait A {
    fn new() -> Self;
}
trait A<T> where T: A<T> {
    fn new() -> T;
}

// return a Self type
struct St1;
impl A<St1> for St1 {
    fn new() -> St1 { St1 }
}

// return a different type
struct St2;
impl A<St1> for St2 {
    fn new() -> St1 { St1 }
}

// won't compile as u32 doesn't implement A<u32>
struct St3;
impl A<u32> for St3 {
    fn new() -> u32 { 0 }
}
例如,这将编译:

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()
}
trait A{
fn new(名称:S)->Self;
fn get_name(&self)->字符串;
}
结构人{
名称:String
}
为某人恳求{
fn新(姓名:S)->个人{
Person{name:name.into()}
}
fn get_name(&self)->字符串{
self.name.clone()
}
}
结构Pet{
名称:String
}
为宠物植入{
fn新(名称:S)->宠物{
Pet{name:name.into()}
}
fn get_name(&self)->字符串{
self.name.clone()
}
}
fn main(){
让人=人::新(“西蒙”);
让宠物=宠物::新的(“伙伴”);
println!(“{}的宠物名为{}”,get_name(&person),get_name(&pet));
}
fn get_name(a:&T)->字符串{
a、 获取名称()
}

作为旁注。。我在这里使用了
String
来支持
&str
引用。。减少对显式生命周期的需要,并可能失去对手头问题的关注。我相信在借用内容时通常会返回
&str
引用,这在这里似乎是合适的。。但是,我不想太过分散对实际示例的注意力。

因为,您当前不能将
impl Trait
放在Trait方法的返回位置

发件人:

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

  • 最终,我们希望允许在traits中使用该特性[…]
现在,您必须使用装箱的trait对象:

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

每晚 如果您希望使用不稳定的夜间功能,可以使用:

//1.40.0-每晚(2019-11-05 1423bec54cf2db283b61)
#![特征(类型\u别名\u实施特征)]
来自未来的特质{
Iter型:迭代器;
fn示例(&self)->self::Iter;
}
u8未来的impl{
Iter类型=impl迭代器;
fn示例(&self)->self::Iter{
标准:iter::重复(*self)。将(*self用作usize)
}
}
fn main(){
对于7.example()中的v{
println!(“{}”,v);
}
}

即使在它不返回
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
    }
}

刚生锈,所以可能需要检查

您可以对返回类型进行参数化。这是有限制的,但比简单地返回
Self
限制要少

trait A {
    fn new() -> Self;
}
trait A<T> where T: A<T> {
    fn new() -> T;
}

// return a Self type
struct St1;
impl A<St1> for St1 {
    fn new() -> St1 { St1 }
}

// return a different type
struct St2;
impl A<St1> for St2 {
    fn new() -> St1 { St1 }
}

// won't compile as u32 doesn't implement A<u32>
struct St3;
impl A<u32> for St3 {
    fn new() -> u32 { 0 }
}
为此,您需要进一步限制类型,例如

trait A<T, U> where U: A<T, U>, T: A<U, T> {
    fn new() -> T;
}
trait A,其中U:A,T:A{
fn new()->T;
}

但我正在努力想办法解决最后一个问题。

这与返回
impl Trait
不同。例如,您无法添加在
Person
中返回
Pet
但在
Pet
中返回
Person
的方法,尽管两者都实现了
a
。提到了这个限制,并表达了最终删除它的愿望(“初始限制”下的第一个项目)。我的回答似乎对OP有所帮助。如果它被接受,我应该如何继续?@SimonWhitehead我建议对第一句话进行编辑(不确定同行评审过程到底是如何工作的,也许你可以看到)。但我认为你的答案很好,没有理由不被接受(毕竟它解决了OP的直接问题)。再次感谢谢普马斯特。我没有完全考虑这一点,所以我发现我的回答没有直接回答这个问题。这就是说,它现在被接受了,似乎对OP有所帮助。我该如何从这里开始?这个问题是否应该被编辑以删除
impl Trait
的特定用法,还是我们应该努力完全删除答案?@SimonWhitehead我不愿意如此彻底地编辑这个问题。我认为两个答案都留下是好的。你可以将答案改为“虽然你还不能做X,但这里有一个解决方法可能会有所帮助”。回答直接问题和提供有用的替代方案都是有价值的贡献。复选标记的主要意思是“这个答案对OP帮助最大”。投票意味着“这个答案帮助了我”。