当前位置: 首页 > 知识库问答 >
问题:

泛型函数可以用特征参数化吗?

田仲卿
2023-03-14

是否可以将特征作为参数传递给这样的泛型函数?

trait Fnord {
    fn do_it(&self) -> i32 { 42 }
}

impl Fnord for i32 {}

fn iter_as<'a, T>(objs: &'a [i32]) -> impl Iterator<Item = & 'a dyn T>
{
    objs.iter().map(|o| o as &dyn T)
}

fn main() {
    let objs: Vec<i32> = vec![1, 2, 3];

    // Calls would look like this
    for s in iter_as::<Fnord>(&objs) {
        println!("{}", s.do_it());
    }
}

这会产生以下错误:

error[E0404]: expected trait, found type parameter `T`
 --> src/lib.rs:7:69
  |
7 | fn iter_as<'a, T>(objs: &'a [i32]) -> impl Iterator<Item = & 'a dyn T>
  |                                                                     ^ not a trait

error[E0404]: expected trait, found type parameter `T`
 --> src/lib.rs:9:35
  |
9 |     objs.iter().map(|o| o as &dyn T)
  |                                   ^ not a trait

warning: trait objects without an explicit `dyn` are deprecated
  --> src/lib.rs:16:24
   |
16 |     for s in iter_as::<Fnord>(&objs) {
   |                        ^^^^^ help: use `dyn`: `dyn Fnord`
   |
   = note: `#[warn(bare_trait_objects)]` on by default

也就是说,iter\u as是否可以接受一个trait作为泛型参数,以便它可以返回该trait的iterable?我一直在寻找答案,但现在我觉得我可能问错了问题。

背景是这样的。我有一个结构,有几个不同具体类型的向量,它们都实现了相同的特性。我希望结构的impl有一个函数,可以返回所有存储对象上的iterable作为它们的任何共同特征。上面的iter_as是该(概念)功能的简化版本。也许我只是用一种笨拙的方式来处理这个问题(也就是说,也许我的思维太像一个C程序员),所以另一种惯用的方法也会很好。

共有1个答案

公孙驰
2023-03-14

T必须是具体类型,而不是特征。我认为,与您所寻找的内容越接近的是:

trait Fnord {
    fn do_it(&self) -> i32;
}

impl Fnord for i32 {
    fn do_it(&self) -> i32 {
        *self
    }
}

impl<'a> From<&'a i32> for &'a dyn Fnord {
    fn from(i: &'a i32) -> Self {
        i as _
    }
}

fn iter_as<'a, T, TObj>(objs: &'a [T]) -> impl Iterator<Item = TObj> + 'a
where
    TObj: 'a,
    TObj: From<&'a T>,
{
    objs.iter().map(|o| o.into())
}

fn main() {
    let objs: Vec<i32> = vec![1, 2, 3];

    for s in iter_as::<i32, &dyn Fnord>(&objs) {
        println!("{}", s.do_it()); // 1 2 3
    }
}

我不确定您是否选择了惯用的生锈方式:因为您知道对象中的具体类型,所以可以按如下方式编写:

trait Fnord {
    fn do_it(&self) -> i32;
}

impl Fnord for i32 {
    fn do_it(&self) -> i32 {
        *self
    }
}

impl<'a> From<&'a i32> for &'a dyn Fnord {
    fn from(i: &'a i32) -> Self {
        i as _
    }
}

struct YourObject {
    v1: Vec<i32>,
    v2: Vec<i32>,
}

impl YourObject {
    fn iter_as<'a, T>(&'a self) -> impl Iterator<Item = T> + 'a
    where
        T: From<&'a i32>, // Add the other bounds you need
    {
        self.v1
            .iter()
            .map(|o| o.into())
            .chain(self.v2.iter().map(|o| o.into()))
    }
}

fn main() {
    let obj = YourObject {
        v1: vec![1, 2],
        v2: vec![3],
    };

    for s in obj.iter_as::<&dyn Fnord>() {
        println!("{}", s.do_it()); // 1 2 3
    }
}

得益于宏,可以减少来自实现样板的

macro_rules! impl_from_for_dyn_trait {
    ( $concrete:ty, $trait:path ) => {
        impl<'a> From<&'a $concrete> for &'a dyn $trait {
            fn from(c: &'a $concrete) -> Self {
                c as _
            }
        }
    }
}

impl_from_for_dyn_trait!(i32, Fnord);

 类似资料:
  • 我有一个设计问题,当使用类似的东西时: 我认为应该有一些更好的方法来实现这种参数化的特性。 我在std中没有找到好的示例(例如,在具有类似的关联类型的traits中没有实现)?

  • 本页包含内容: 泛型形参子句 泛型实参子句 本节涉及泛型类型、泛型函数以及泛型构造器的参数,包括形参和实参。声明泛型类型、函数或构造器时,须指定相应的类型参数。类型参数相当于一个占位符,当实例化泛型类型、调用泛型函数或泛型构造器时,就用具体的类型实参替代之。 关于 Swift 语言的泛型概述,见泛型(第二部分第22章)。 泛型形参子句 泛型形参子句指定泛型类型或函数的类型形参,以及这些参数的关联约

  • 我不想为每个类型T编写这个方法只是为了调用getMessage()并将其传递给下一个方法。 有可能写出这样的方法吗?我只想访问ConstraintViolation接口的方法,这些方法不依赖于类型T(如字符串getMessage())。

  • 同样的规则也可以适用于函数:在使用前给出 <T> 后,类型 T 就变成了泛型。 使用泛型函数有时需要显式地指明类型参量。这种可能的情况包括,调用返回类型是泛型的函数,或者编译器没有足够的信息来推导类型参量。 函数调用使用显式指定的类型参量,如下所示: fun::<A, B, ...>(). struct A; // 具体类型 `A`。 struct S(A); //

  • 问题内容: 我想知道是否有可能编写一个接受多种通用类型的函数,如下所示: 那行得通吗?每个参数中的泛型是否意味着每个参数必须具有与泛型相同的类型T? 问题答案: 是的-可能的(虽然不是使用方法签名),是的,使用签名的类型必须相同。 使用给定的签名,必须在呼叫站点将其与单个类型(例如 或 )相关联。但是,您可以声明采用多个类型参数的方法签名 请注意,在上面的签名中,我已经声明了类型以及签名本身。因此

  • 所以我有那个代码,我是通过上传到Imgur v3使用Javahttps错误得到的,我在第50行得到一个错误,因为“列表”告诉我 类型列表不是泛型的;它不能用参数参数化 我能做些什么来解决这个问题? 我正在使用http://hc.apache.org/httpclient-3.x/并希望使用v3 API将图像上传到imgur。 编辑:更改导入后,我现在收到这些错误。 这就解决了这个问题,但又给了我两