【问题标题】:How do I coerce types of iterator elements to & from a newtype?如何将迭代器元素的类型强制转换为新类型?
【发布时间】:2019-06-06 06:21:28
【问题描述】:

用新类型做一些实验,寻找最有效、最符合人体工程学的方法来处理集合中的元素转换。对于奇异值,相当标准的类型转换特征似乎工作得很好:

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 无法将 tags 强制转换为 Vec&lt;String&gt;,我觉得应该有一些比以下更容易的方法:

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

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

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

【问题讨论】:

标签: vector collections rust type-conversion newtype


【解决方案1】:

简单,只使用泛型:

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>,
{
    // ...
}

【讨论】:

  • 我明白了!谢谢你。所以,为了清楚起见,str / String 与其说是[T] / Vec&lt;T&gt; 的罪魁祸首,对吧?而且我还认为如果不更改被调用函数的定义(在本例中为process_array_of_strings)就无法缓解这种情况,这就是为什么不鼓励使用非泛型形式的原因?
  • @pospi 如果你想使用 trait,使用泛型是最简单且零成本的解决方案。
  • 是的,我明白了。我要说的是,在这种特殊情况下(我刚刚通过尝试确认),实际上并不是String 阻止了转换为process_array_of_strings 的工作。它可以与String 一起工作,只是效率不高。 Vec&lt;T&gt; 参数类型意味着参数不能被强制,因为包装类型妨碍了类型推断。
猜你喜欢
  • 1970-01-01
  • 2020-06-24
  • 1970-01-01
  • 2014-02-04
  • 1970-01-01
  • 1970-01-01
  • 2020-02-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多