我如何制作格式! return 来自条件表达式的 &str?
How do I make format! return a &str from a conditional expression?
我遇到了这个问题,据我所知,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()
在模式中每个文字的末尾,因为它不那么干净。
有没有办法解决这个问题,还是我只需要解决这个问题?
这是 的 90% 重复,请参阅其他多个解决方案。
还有一种额外的可能性,因为这一切都在一个函数中:您可以为 String
声明一个变量,并且只在需要分配时设置它。编译器(倾斜地)建议:
consider using a let
binding to create a longer lived value
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
基本相同,只是由编译器处理,而不是特定类型。
另请参阅:
format!
不能 return &str
因为它总是会分配 String
。可以做的是 return 从 String
到 &str
,这就是您在代码中所做的。
正如编译器所暗示的那样,创建的 String
在创建后立即被删除,因为它超出了当前范围,一种解决方法可能是不受限于 [=18= 的外部变量] 范围。例如:
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);
}
以我为例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),
}
}
我遇到了这个问题,据我所知,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()
在模式中每个文字的末尾,因为它不那么干净。
有没有办法解决这个问题,还是我只需要解决这个问题?
这是
还有一种额外的可能性,因为这一切都在一个函数中:您可以为 String
声明一个变量,并且只在需要分配时设置它。编译器(倾斜地)建议:
consider using a
let
binding to create a longer lived value
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
基本相同,只是由编译器处理,而不是特定类型。
另请参阅:
format!
不能 return &str
因为它总是会分配 String
。可以做的是 return 从 String
到 &str
,这就是您在代码中所做的。
正如编译器所暗示的那样,创建的 String
在创建后立即被删除,因为它超出了当前范围,一种解决方法可能是不受限于 [=18= 的外部变量] 范围。例如:
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);
}
以我为例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),
}
}