我碰到了这个问题,据我所知,format!
在一个不固定于任何内容的模式中创建了一个临时值。
let x = 42;
let category = match x {
0...9 => "Between 0 and 9",
number @ 10 => format!("It's a {}!", number).as_str(),
_ if x < 0 => "Negative",
_ => "Something else",
};
println!("{}", category);
在此代码中,category
的类型为&str
,这可以通过返回类似"Between 0 and 9"
的文字来满足。如果我想使用as_str()
将匹配的值格式化为切片,则会出现错误:
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:5:24
|
3 | let category = match x {
| -------- borrow later stored here
4 | 0...9 => "Between 0 and 9",
5 | number @ 10 => format!("It's a {}!", number).as_str(),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
|
= note: consider using a `let` binding to create a longer lived value
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
我已经读了一些书,发现有类似问题的人,但是我似乎找不到任何解决方法。
一个简单的解决方法是让category
成为String
而不是&str
,但是我不喜欢必须将.to_string()
放在模式中每个文字的结尾,因为它不是那么干净。
是否有解决问题的方法,还是我只需要解决它?
答案 0 :(得分:3)
这是Return local String as a slice (&str)的90%重复,请参见其他解决方案的说明。
还有另一种可能,因为这是一个功能:您可以为String
声明一个变量,并且仅在需要分配时设置它。编译器(倾斜地)建议:
考虑使用
let
绑定来创建寿命更长的值
fn main() {
let x = 42;
let tmp;
let category = match x {
0...9 => "Between 0 and 9",
number @ 10 => {
tmp = format!("It's a {}!", number);
&tmp
}
_ if x < 0 => "Negative",
_ => "Something else",
};
println!("{}", category);
}
这与使用Cow
几乎相同,只是由编译器而不是特定类型来处理。
答案 1 :(得分:1)
format!
无法返回&str
,因为它将始终分配String
。可以做的是从&str
返回一个String
,这就是您在代码中所做的。
正如编译器所提示的那样,创建的String
在创建之后会立即被删除,因为它超出了当前范围,并且一种解决方法可能是不受限于match
范围的外部变量。例如:
use std::fmt::Write;
fn main() {
let mut buffer = String::with_capacity(20);
buffer.push_str("It's a ");
let x = 10;
let category = match x {
0...9 => "Between 0 and 9",
number @ 10 => {
write!(&mut buffer, "{}", number).unwrap();
buffer.as_str()
}
_ if x < 0 => "Negative",
_ => "Something else",
};
println!("{}", category);
}
如果您想要一个[no_std]
环境或不想进行任何动态分配,则可以查看以下受限代码段:
use core::str;
fn each_digit<F>(mut number: u32, mut f: F)
where
F: FnMut(u8),
{
while number > 0 {
f((number % 10) as u8);
number /= 10;
}
}
fn main() {
const BUFFER_LEN: usize = 20;
let mut buffer = [0u8; BUFFER_LEN];
let x = 12344329;
let category = match x {
0...9 => "Between 0 and 9",
number @ 123443219 => {
let mut idx = BUFFER_LEN;
each_digit(number, |digit| {
let ascii = digit + 48;
idx -= 1;
buffer[idx] = ascii;
});
str::from_utf8(&buffer[idx..BUFFER_LEN]).unwrap()
},
_ => "Something else",
};
assert_eq!("123443219", category);
}
答案 2 :(得分:0)
就我而言,How to overcome "temporary value dropped while borrowed" when converting an i32 to &str
我可以通过在分支内移动呼叫来解决它
pub fn uidl(&mut self, message_number: Option<i32>) -> POP3Result {
let command = match message_number {
Some(_) => POP3Command::UidlOne,
None => POP3Command::UidlAll,
};
match message_number {
Some(i) => {
// Here the value is not dropped because it is not leaving the scope
self.execute_command(command, Some(arg.to_string().as_str()))
}
// Here I had to duplicate the call
None => self.execute_command(command, None),
}
}