如何为rust trait边界指定多种可能性

ssm49v7z  于 2024-01-08  发布在  其他
关注(0)|答案(1)|浏览(125)

我正在尝试编写一个函数,该函数接受泛型类型的任何可迭代对象作为输入,并在元素上循环。

pub fn test1<'a, IterableT, ItemT>(nodes: &'a IterableT)
    where 
        &'a IterableT: IntoIterator<Item = &'a ItemT>,
        ItemT: 'a + Debug
    {
        for x in nodes {
            println!("consuming or iterating: {:?}!", x);
        }
    }

字符串
这适用于引用类型。我努力实现一个既适用于常规类型又适用于引用的版本。

pub fn test1<IterableT>(nodes: IterableT)
    where 
        IterableT: IntoIterator,
        IterableT::Item: Debug
    {
        for x in nodes {
            println!("consuming or iterating: {:?}!", x);
        }
    }


只要我使用的类型的引用版本实现了IntoIterator(例如vec&vec&mut vec),这就可以工作。问题是我不能重新引入ItemT泛型,因为基础Item被缩小到Item&Item之一

pub fn test1<IterableT, ItemT>(nodes: IterableT)
    where 
        IterableT: IntoIterator<Item = ItemT>, // alternatively IntoIterator<Item = &ItemT>
        ItemT: Debug
    {
        for x in nodes {
            println!("consuming or iterating: {:?}!", x);
        }
    }


取决于我使用的是IntoIterator<Item = ItemT>还是IntoIterator<Item = &ItemT>,这适用于vec&vec,但不能同时适用。一个简单的解决方法是指定IterableT::Item: Into<ItemT>,但这只有在底层类型实现Into traits时才有效(因此这将适用于内置类型,如i32,i64,但不适用于某些自定义结构)。
有没有一种方法可以在where子句中指明Item可以是ItemT&ItemT?我需要引入ItemT的原因是因为它是父结构的泛型变量,这个函数是它的一部分。我需要接受特定类型的迭代器。

9jyewag0

9jyewag01#

您可以使用std::borrow::BorrowT&T视为相同。

use std::{borrow::Borrow, fmt::Debug};

fn debug_iterator<I, T>(it: I)
where
    I: IntoIterator,
    I::Item: Borrow<T>,
    T: Debug + ?Sized,
{
    for item in it.into_iter() {
        println!("  item: {:?}", item.borrow());
    }
}

字符串
实际:

fn main() {
    let v1 = vec![String::from("hello"), String::from("world")];

    println!("By reference:");
    debug_iterator::<_, String>(v1.iter());
    
    println!("By value:");
    debug_iterator::<_, String>(v1);
}


输出量:

By reference:
  item: "hello"
  item: "world"
By value:
  item: "hello"
  item: "world"


注意,因为Borrow trait有一个type参数,所以你必须在调用站点显式地为T提供正确的类型; Rust将无法推断出你想要的类型。

相关问题