我有一个变量tokens: &[AsRef<str>],我想将它连接到单个字符串中:
// tokens: &[AsRef<str>]
let text = tokens.join("") // Error
let text = tokens.iter().map(|x|x.as_ref()).collect::<Vec<_>>().join("") // Ok, but...第二种是尴尬和低效的,因为它将项重新分配给新的Vec。
根据源代码的说法,如果join的类型是&[Borrow<str>],则它可以应用于tokens。
// if tokens: &[Borrow<str>]
let text = tokens.join("") // OK
// so I want to convert &[AsRef<str>] to &[Borrow<str>]
let text = convert_to_borrow(tokens).join("")我该怎么做?为什么Join是为实现Borrow而不是AsRef的类型实现的
发布于 2020-08-04 12:35:26
它可能稍微慢一些,但您可以将collect迭代器的&strs直接放入String中。
let text: String = tokens.iter().map(|s| s.as_ref()).collect();这是可能的,因为FromIterator<&'_ str>。此方法通过反复调用String来增长push_str,这可能意味着必须多次重新分配它,但它不会创建中间Vec<&str>。取决于所使用的片和字符串的大小,这可能要慢一些(虽然在某些情况下也可以稍微快一些)。如果差异对您有重大意义,您应该对这两个版本进行基准测试。
没有办法把T: AsRef<str>的一个片段当作T: Borrow<str>的一个片段,因为并不是所有实现AsRef的东西都实现了Borrow,所以在泛型代码中,编译器无法知道要应用什么Borrow实现。
发布于 2020-08-04 15:47:07
Trentcl的回答仅依靠AsRef<str>实现为您的实际问题提供了解决方案。下面更多的是对标题中更一般性问题的回答。
某些特性带有不变量,实现必须执行这些不变量。特别是,如果Borrow<T>的实现也实现了Eq、Hash和Ord,那么对于T的这些特性的实现必须是相同的。这一要求是指借来的价值与原始价值“相同”,但只是以另一种方式看待。例如,String: Borrow<str>实现必须返回整个字符串片;返回子片是不正确的。
AsRef没有这个限制。AsRef<T>的实现可以以与T完全不同的方式实现Hash和Eq等特性。如果您需要返回对结构的一部分的引用,那么AsRef可以这样做,而Borrow不能。
所有这一切都意味着您无法从任意的Borrow<T>实现中派生出有效的AsRef<T>实现:AsRef实现可能不会强制执行Borrow所需的不变量。
然而,相反的方法是有效的。给定任意的AsRef<T>,您可以创建Borrow<T>的实现。
use std::borrow::Borrow;
use std::convert::AsRef;
use std::marker::PhantomData;
pub struct BorrowAsRef<'a, T: ?Sized, U: ?Sized>(&'a T, PhantomData<U>);
impl<'a, T, U> AsRef<U> for BorrowAsRef<'a, T, U>
where
T: Borrow<U> + ?Sized,
U: ?Sized,
{
fn as_ref(&self) -> &U {
self.0.borrow()
}
}
pub trait ToAsRef<T: ?Sized, U: ?Sized> {
fn to_as_ref(&self) -> BorrowAsRef<'_, T, U>;
}
impl<T, U> ToAsRef<T, U> for T
where
T: ?Sized + Borrow<U>,
U: ?Sized,
{
fn to_as_ref(&self) -> BorrowAsRef<'_, T, U> {
BorrowAsRef(self, PhantomData)
}
}fn borrowed(v: &impl Borrow<str>) {
needs_as_ref(&v.to_as_ref())
}
fn needs_as_ref(v: &impl AsRef<str>) {
println!("as_ref: {:?}", v.as_ref())
}为什么
Join是为实现Borrow而不是AsRef的类型实现的?
对于所有实现Borrow<str>的类型,这都是一个全面的实现,这意味着它也不能为实现AsRef<str>的类型实现。即使启用了不稳定的特性min_specialization,它也无法工作,因为拥有AsRef的实现并不比拥有Borrow的实现更“特定”。所以他们必须选择一个或另一个。
可以说,AsRef是一个更好的选择,因为它涵盖了更多的类型。但不幸的是,我不认为这一点现在可以改变,因为这将是一个巨大的变化。
https://stackoverflow.com/questions/63246747
复制相似问题