如何强制迭代器元素的类型与新类型相提并存?



对newtypes进行一些实验,并寻找最有效,最符合人体工程学的方式来处理转换集合中的元素。对于奇异值,非常标准的类型转换特征似乎工作得很好:

pub struct Tag(String);
impl From<Tag> for String {
fn from(v: Tag) -> String {
v.0
}
}
impl From<String> for Tag {
fn from(v: String) -> Tag {
Tag(v)
}
}
impl AsRef<String> for Tag {
fn as_ref(&self) -> &String {
&self.0
}
}
impl<'a> From<&'a Tag> for String {
fn from(t: &Tag) -> String {
t.0.clone()
}
}

但是,当我想处理项目列表时,我开始遇到问题。假设(为了说明目的)我有一个处理标签的函数,以及一些更抽象的函数来处理将字符串写入数据库:

fn process_item(tags: &Vec<Tag>) {
process_array_of_strings(tags);
}
fn process_array_of_strings(strings: &Vec<String>) {
// ...
}

这不会编译,因为 Rust 不能强制tagsVec<String>,在我看来,应该有某种方法

比:
fn process_item(tags: &Vec<Tag>) {
let str_tags: Vec<String> = tags.iter().map(|t| t.into()).collect();
process_array_of_strings(&str_tags);
}

。除了冗长之外,它还涉及比我想要的更多的中间记忆。反向转换也是一个问题,但大概会以同样的方式实现。

这里可能还有一些其他事情在起作用,例如我是否应该发送Vec引用而不是值,以及从引用类型实现类型转换是否是一个好主意。

很简单,只需使用泛型:

pub struct Tag(String);
impl AsRef<str> for Tag {
fn as_ref(&self) -> &str {
&self.0
}
}
fn process_item(tags: &[Tag]) {
process_array_of_strings(tags);
}
fn process_array_of_strings<'a, T>(strings: &[T])
where
T: AsRef<str>,
{
// ...
}
  • 为什么不鼓励接受对字符串(&String)、Vec(&Vec)或Box(&Box)的引用作为函数参数?
  • 在这里,我们只是要求T实现AsRef<str>(比String更通用),以便您可以在之后使用as_ref()

最新更新