我正在为我自己的结构实现一个自定义Display::fmt
,它代表一个区间。
struct Range<T> {
lower: Option<T>,
upper: Option<T>,
}
范围可以是Range { lower: Some(1), upper: None }
,这意味着它包含从1到无穷大的所有整数(或者我认为的i32
的限制)。
如果绑定不是Display::fmt
,我想实现T
使用Display::fmt
&#39; s None
,否则显示空字符串:
let range = Range { lower: Some(1), upper: None }
println!("{}", range); // Prints <1,>
let range = Range { lower: Some(1), upper: Some(10) }
println!("{}", range); // Prints <1,10>
let range = Range { lower: None, upper: Some(10) }
println!("{}", range); // Prints <,10>
我已经开始实施,但是match
表达式和format!()
生成的字符串的生命周期有问题。我的实现问题是格式返回的字符串不能长时间使用,以便进一步使用。
fn main() {
let opt = Some(1);
let opt_display = match opt {
Some(x) => &format!("{}", x), // error: borrowed value does not live long enough
None => "",
};
println!("opt: {}", opt_display);
}
为什么我的方法不起作用,什么是解决我问题的好方法?
答案 0 :(得分:5)
我不是终身专家,但我相信这里的问题是你试图从匹配中&String
创建的String
返回format!
。由于格式的范围仅在范围内,借用检查员会抱怨。
要解决此问题,您可以使用拥有的字符串。
fn main() {
let opt = Some(1);
let opt_display = match opt {
Some(ref x) => format!("{}", x), // Allowed since opt_display now owns the string
None => "".into(),
};
// Another way to achieve the same thing.
//let opt_display = opt.map(|s| format!("{}", s)).unwrap_or("".into());
println!("opt: {}", opt_display);
}
答案 1 :(得分:3)
实现Display
时,不需要返回字符串;您只需write!()
进入提供的格式化程序。
看起来像是:
impl<T: Display> Display for Range<T> {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), std::fmt::Error> {
write!(fmt, "<")?;
if let Some(v) = self.lower {
write!(fmt, "{}", v)?;
}
write!(fmt, ",")?;
if let Some(v) = self.upper {
write!(fmt, "{}", v)?;
}
write!(fmt, ">")
}
}
答案 2 :(得分:2)
作为Emilgardis has already explained,您尝试返回对引用仍然存在时将丢弃的值的引用。恭喜你,你只是试图创造内存不安全,这会导致C或C ++崩溃(或更糟),但Rust阻止了它!
您可以提高效率只是在一种情况下进行分配:
fn main() {
let opt = Some(1);
let opt_display = opt.map(|s| format!("{}", s));
// Type not needed, only used to assert the type is what we expect
let opt_display_str: &str = opt_display.as_ref().map(String::as_str).unwrap_or("");
println!("opt: {}", opt_display_str);
}
您还可以使用Cow
,它允许拥有或借用字符串。请注意它与其他答案的相似程度,但在None
的情况下,这不会分配:
use std::borrow::Cow;
fn main() {
let opt = Some(1);
let opt_display: Cow<str> = match opt {
Some(ref x) => format!("{}", x).into(),
None => "".into(),
};
println!("opt: {}", opt_display);
}
我想实施
Display::fmt
最佳要做的事情可能是避免任何分配。您将获得write!
的格式化程序,只需在每个匹配组中调用write!
即可。这可能会引入一些重复,但可能更有效。没有格式化程序,它看起来像:
fn main() {
let opt = Some(1);
print!("opt: ");
if let Some(ref x) = opt {
print!("{}", x);
}
println!("");
}
在格式化程序中替换write!(f,
print!(
并返回错误。