我的代码中有一个函数,它接受一个&[&'a str]
:
fn user_quicksort<'a>(list: &[&'a str]) -> Vec<&'a str>
在调用者中,我有一个Box<[Box<str>]>
变量,我想传递给它;然而,Rust给了我以下错误:
error[E0308]: mismatched types
--> src\main.rs:36:33
|
36 | let sorted = user_quicksort(&input);
| -------------- ^^^^^^ expected `&[&str]`, found `&Box<[Box<str>]>`
| |
| arguments to this function are incorrect
|
= note: expected reference `&[&str]`
found reference `&Box<[Box<str>]>`
我使用Box<str>
而不是String
的原因是因为Box<str>
是不可变的,更快,更小。
我该怎么办?
下面是如何得到input
:
let input = fs::read_to_string("input.txt")
.expect("Unable to read file")
.split("\n")
.map(|s| s.to_string().into_boxed_str())
.collect::<Box<[Box<str>]>>();
2条答案
按热度按时间fhity93d1#
错误消息显示,Rust期望得到一个对字符串引用切片(
&[&str]
)的引用,但实际上它得到了一个对装箱字符串切片(&Box<[Box<str>]>
)的引用。类型不匹配。要解决这个问题,您需要在将
Box<str>
传递给函数之前将其解引用到str
中。下面是你如何做到这一点:它的作用:
iter()
在input
的元素上创建一个迭代器。map(|s| &**s)
获取每个Box<str>
,解引用它两次(**s
)以获得str
,然后引用它(&
),得到&str
。collect::<Vec<&str>>()
将结果&str
s收集到Vec<&str>
中。&
引用Vec<&str>
,得到&[&str]
,这是user_quicksort
所期望的。这段代码创建了一个临时的
Vec<&str>
,以便将&[&str]
传递给user_quicksort
。重要的是要注意,&str
的寿命与input
相关,因此Vec<&str>
不能超过input
。也就是说,如果您的用例允许的话,将
user_quicksort
更改为采用&str
s的迭代器而不是切片可能会更有效。这样可以避免创建临时向量。新的函数签名可能看起来像这样:你可以这样称呼它:
这允许更大的灵活性和潜在的更好的性能,但它是否合适取决于您的特定用例。
编辑后:
如果您正在阅读一个文件,然后将行转换为
Box<str>
,并且您不想创建中间Vec<&str>
,则可以将input
的类型更改为Vec<Box<str>>
而不是Box<[Box<str>]>
。通过这种方式,您可以直接从它创建一个字符串引用片段(&[&str]
),而无需任何堆分配。以下是如何调整代码:
这将在堆栈上创建一个临时切片,而不是
Vec<&str>
。collect::<&[_]>()
函数将创建一个临时切片,您可以将其传递给user_quicksort
函数。这避免了Vec<&str>
的堆分配,并且应该满足您的性能要求。请注意,这只是因为您立即使用切片,而不是试图从函数返回或存储在某个地方。切片仅在
input
(及其包含的Box<str>
值)在作用域中且未被修改时有效。如果您需要切片的生存时间长于input
或在input
被修改后仍然存在,则需要使用不同的方法。jxct1oxe2#
我不想在排序函数中强加一个重复的序列,而是让它对序列进行排序原地。
这样,在调用位点,我们可以选择是否要改变原始序列,或者我们是否要保持它未排序并构建要排序的浅拷贝。
克隆序列的成本很高,因为每个
Box<str>
也会被克隆。那么我们的排序函数应该能够处理原始序列的Box<str>
序列和浅拷贝的&str
序列。在参数中使用impl AsRef<str>
很有帮助,因为Box<str>
和&str
(显然)都可以被认为是对str
的引用。