fn problem() -> Vec<&'static str> {
let my_string = String::from("First Line\nSecond Line");
my_string.lines().collect()
}
Run Code Online (Sandbox Code Playgroud)
这失败并出现编译错误:
|
7 | my_string.lines().collect()
| ---------^^^^^^^^^^^^^^^^^^
| |
| returns a value referencing data owned by the current function
| `my_string` is borrowed here
Run Code Online (Sandbox Code Playgroud)
我明白这个错误意味着什么 - 它是为了阻止你返回对超出范围的值的引用。查看所涉及函数的类型签名后,问题似乎出在lines方法上,该方法借用了调用它的字符串。但这有什么关系呢?我正在遍历字符串的行以获取部件的向量,我返回的是这个“新”向量,而不是任何会(非法)直接引用my_string
.
(我知道我可以很容易地通过使用字符串文字而不是转换为“拥有”的字符串来修复这个特定的例子String::from
。这是一个重现问题的玩具示例——在我的“真实”代码中,字符串变量是从文件中读取,所以我显然不能使用文字。)
对我来说更神秘的是,对我来说应该遇到同样问题的函数的以下变化可以正常工作:
fn this_is_ok() -> Vec<i32> {
let my_string = String::from("1\n2\n3\n4");
my_string.lines().map(|n| n.parse().unwrap()).collect()
}
Run Code Online (Sandbox Code Playgroud)
原因不能map
做一些魔术,因为这也失败了:
fn also_fails() -> Vec<&'static str> {
let my_string = String::from("First Line\nSecond Line");
my_string.lines().map(|s| s).collect()
}
Run Code Online (Sandbox Code Playgroud)
我已经玩了很长一段时间了,在里面尝试了各种不同的功能map
- 有些通过,有些失败,老实说,我不知道有什么区别。所有这一切让我意识到,我对 Rust 的所有权/借用规则在非平凡情况下的工作方式知之甚少,尽管我认为我至少了解了基础知识。因此,如果有人能给我一个相对清晰和全面的指南,说明所有这些示例中发生的事情,以及如何以某种直接的方式修复那些失败的示例,我将不胜感激!
关键在于lines
:产生的值的类型&str
。为了避免不必要的克隆,lines
实际上返回对其调用的字符串切片的引用,并且当您将其收集到 a 时Vec
,该Vec
元素只是对字符串切片的引用。所以,当然,当你的函数退出并且字符串被删除时,里面的引用Vec
将被删除并且无效。请记住,&str
是借用字符串,并且String
是自有字符串。
解析工作是因为您将这些&str
s 读入 一个i32
,因此数据被传输到一个新值并且您不再需要对原始字符串的引用。
要解决您的问题,只需使用str::to_owned
将每个元素转换为String
:
fn problem() -> Vec<String> {
let my_string = String::from("First Line\nSecond Line");
my_string.lines().map(|v| v.to_owned()).collect()
}
Run Code Online (Sandbox Code Playgroud)
应该注意的是,它to_string
也有效,这to_owned
实际上是ToOwned
trait 的一部分,因此它对其他借用类型也很有用。
对于对大小值的引用(str
未调整大小,因此这不适用),例如Iterator<Item = &i32>
,您可以简单地使用Iterator::cloned
克隆每个元素,使它们不再是引用。
另一种解决方案是将 theString
作为参数,因此它以及对它的引用可以超过函数的作用域:
fn problem(my_string: &str) -> Vec<&str> {
my_string.lines().collect()
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
83 次 |
最近记录: |