在Trait定义中使用impl Trait

时间:2016-09-14 03:38:26

标签: rust traits

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

#![feature(conservative_impl_trait)]

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

但是,我收到以下错误:

  

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

这只是Rust当前执行impl Trait的限制还是我使用它错了?

4 个答案:

答案 0 :(得分:21)

作为trentcl mentions,您目前无法将impl Trait置于特征方法的返回位置。

来自RFC 1522

  

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

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

目前,您必须使用盒装特征对象:

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

另见:

仅限夜间

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

#![feature(existential_type)]

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

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

impl FromTheFuture for u8 {
    existential type Iter: 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);
    }
}

答案 1 :(得分: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引用通常是惯例,这似乎是合适的。但是我不想过多地分散实际例子。

答案 2 :(得分:5)

即使在未返回&#34; Self&#34;的情况下,您也可以通过明确命名返回类型来获得类似的内容。

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

答案 3 :(得分:0)

Rust尚不成熟,因此可能需要检查。

您可以对返回类型进行参数化。这是有限制的,但是与只返回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 } } 相比,它们的限制要少。

T

在这种情况下,限制是您只能返回实现A<T>的类型St1。在这里,A<St1>实现了St2,因此impl A<St2>impl A<St1> for St2 ... impl A<St2> for St1 ... 可以。但是,它不适用于例如

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

为此,您需要进一步限制类型,例如

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import geopandas as gpd
import descartes
from shapely.geometry import Point, Polygon

df = gpd.read_file('mesh.shp')
Z_values = pd.read_csv('Na_values.csv', delimiter='\t')
df['elevation']=None
for index, row in df.iterrows():
    df.loc[index,'elevation'] = Z_values.loc[index,'value']
df.plot(column='elevation',cmap='terrain')```

Here is how the output looks like and I just want to add an interactive colorbar to this map.
[![enter image description here][1]][1]


  [1]: https://i.stack.imgur.com/npYgf.png

但是我正在努力使最后一个回合。