将 Vec<Cow<'_, [u8]> 转换为 &str

时间:2021-05-29 09:00:56

标签: rust

一个 lib (quick_xml) 函数 (attributes()) 返回一个类型为 Vec<Cow<'_, [u8]> 的值。

确切的行是 e.attributes().map(|a| a.unwrap().value).collect::<Vec<_>>(),打印的值 = [[116, 101, 115, 116]]

如何将其转换为字符串(在本例中为“test”)以便稍后使用?

2 个答案:

答案 0 :(得分:2)

我假设您引用的是 this example。以后,请给我们完整的源代码 - 这样可以更轻松地回答问题。


理解代码

让我们一步一步来:

  1. e.attributes().map(|a| a.unwrap().value).collect::<Vec<_>>()
    ^
    

    e 是一个 BytesStart struct,所以它代表一个开始的 XML 标记,在你的例子中是 <tag1 att1 = "test">

  2. e.attributes().map(|a| a.unwrap().value).collect::<Vec<_>>()
      ^^^^^^^^^^^^
    

    这是the attributes method of BytesStart。它返回 the Attributes struct 表示一个标签具有的一组属性。在您的情况下,这只是一个属性:它具有名称 attr1 和值 test

    Attributes is an iterator,这意味着您可以迭代包含的 Attribute(注意 Attributes 包含多个 Attribute - 这些不是同一类型!)。如果您想了解有关迭代器的更多信息,您可能需要阅读 the chapter about it in the Rust book

  3. e.attributes().map(|a| a.unwrap().value).collect::<Vec<_>>()
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
    

    这里,我们称 the map method of the Iterator struct。它允许我们通过转换迭代器的每个值来将一个迭代器(在本例中为 Attributes 结构体)转换为另一个迭代器。我们用一个闭包(如果你不知道这是什么,the Rust book also has a chapter about this)来调用它,它接受原始迭代器的一个值并返回新迭代器的转换值。现在,让我们看看那个迭代器:

    1. |a| a.unwrap().value
      ^^^
      

      这个迭代器接受一个名为 a 的参数,正如我上面所说的,它是原始迭代器包含的类型。我在上面说过 Attributes 包含多个 Attribute - 虽然这是真的,但它不是全貌,迭代器迭代 Result<Attribute>,这就是 {{1} 的类型}.

    2. a

      正常运行时,|a| a.unwrap().value ^^^^^^^^^^ 将始终是包含您的 aResult::Ok 实例,但如果您的 XML 以某种方式无效,Attribute 也可能是一个 {{ 3}} 表示某种解析错误。我们不想关心这里的错误处理,所以我们只调用 Result::Err 返回包含的 a 并在出现错误时发生恐慌。

    3. Argument

      |a| a.unwrap().value ^^^^^ 结构体包含两个值:the unwrap method of Result 和 [Attribute]。我们只对 value 感兴趣,所以让我们选择它。 value 字段的类型为 value。 Cow 是一个智能指针,具有一些在这里并不真正相关的有趣属性。如果你想了解更多,你可能会对 key 感兴趣(尽管他对 Rust 新手来说可能有点太复杂了)。对于本说明的其余部分,我将假设 Cow<'a, [u8]> 属于 value 类型(对 &[u8] 切片的引用)。

    4. 我们现在已经确定闭包返回一个 u8,因此 &[u8] 返回的迭代器迭代 map

  4. &[u8]

    现在我们调用 the documentation of Cow 将迭代器转换为集合。集合的类型作为泛型参数给出,为 e.attributes().map(|a| a.unwrap().value).collect::<Vec<_>>() ^^^^^^^^^^^^^^^^^^^ 。下划线告诉 rustc 尝试通过上下文找出正确的类型,如果不可能,则输出错误。此处唯一可能的类型是 Vec<_>,因此,此方法返回 &[u8]

解决办法

您可以使用 the collect method of Iterator。这会将 Vec<&[u8]> 值转换为 Attribute,并且如果属性包含转义序列,也会取消转义它们。

String

请注意,这仍然返回 e.attributes().map(|a| a.unwrap().unescape_and_decode_value(&reader).unwrap()).collect::<Vec<_>>() ,而不是 Vector<String>。该向量包含分配给该元素的所有属性的值——在本例中,它只是属性值“Test”。

答案 1 :(得分:1)

您可以使用 std::str::from_utf8&[u8] 错误地转换为 &str

use std::borrow::Cow;

fn main() {
    let s = "test";
    let v = s.as_bytes();
    let c = Cow::Borrowed(v);
    println!("{}", std::str::from_utf8(&*c).unwrap());
}

关键部分是 Cow 的取消引用和重新借用,因为 from_utf8 使用 &[u8] 而不是 CowCowDeref 实现 T,在这种情况下 T[u8],因此您可以通过 &[u8] 获得 &*

Playground Link

在您的具体示例中,您应该能够通过以下方式获得 Vec<&str>

e.attributes().map(|a| std::str::from_utf8(&*a.unwrap().value).unwrap()).collect::<Vec<_>>()