以下Python代码返回第一个非空字符串(在此示例中为bar
的内容):
foo = ""
bar = "hello"
foo or bar # returns "hello"
如何在Rust中编写它?我试过这个:
let foo = "";
let bar = "";
foo || bar;
但我得到了这个
error[E0308]: mismatched types
--> src/main.rs:4:5
|
4 | foo || bar;
| ^^^ expected bool, found &str
|
= note: expected type `bool`
found type `&str`
我想我不能轻易做我在Python中用Rust做的事情吗?
答案 0 :(得分:4)
Rust没有像Python这样的 truthy 或 falsy 值的概念,所以你不能使用str
作为布尔值。事实上,除了实际的bool和比较运算符之外,你不能使用任何东西。
使用match
的{{3}}的替代方法是
let result = match (foo.is_empty(), bar.is_empty) {
(true,_) => Some(foo),
(_, true) => Some(bar),
_ => None,
};
如果您想要多种字符串的此类型或功能,可以使用宏:
macro_rules! first_nonempty {
( $( $string:expr),+ )=> ({
$(
if !$string.is_empty() {
Some($string)
} else
)+
{ None }
})
}
像这样使用
let res = first_nonempty!("foo", "bar", ""); // res is Some("foo")
let res = first_nonempty!("", "bar", "baz", "quux"); // res is Some("bar")
let res = first_nonempty!(""); // res is None
答案 1 :(得分:3)
如果你有几个字符串,我会使用迭代器;
let strs = ["", "foo", "bar"];
let non_empty = strs.iter().skip_while(|&x| x.is_empty()).next();
println!("{}", non_empty.unwrap_or(&""));
如果您经常使用它,它也可以进入它自己的功能:
// call as let non_empty = first_non_empty(&["", "foo", "bar"]);
fn first_non_empty<'a>(strs: &[&'a str]) -> &'a str {
strs.iter().skip_while(|&x| x.is_empty()).next().unwrap_or(&"")
}
答案 2 :(得分:3)
您还可以创建一个可以添加所需行为的扩展特征:
trait Or: Sized {
fn or(self, other: Self) -> Self;
}
impl<'a> Or for &'a str {
fn or(self, other: &'a str) -> &'a str {
if self.is_empty() { other } else { self }
}
}
现在您可以像这样使用它:
assert_eq!("foo".or("bar"), "foo");
assert_eq!("".or("").or("baz").or("").or("quux"), "baz");
如果您需要确保第二个参数被懒惰地评估,您可以使用以下方法扩展Or
特征:
fn or_else<F: FnOnce() -> Self>(self, f: F) -> Self;
有关详细信息,请参阅Option
:Option#or
和Option#or_else
的类似方法。
答案 3 :(得分:1)
这里的问题是Rust不会在逻辑表达式中隐式地将字符串(或其他任何东西)转换为布尔值。
如果你想模仿Python的行为,即你想在你的布尔表达式之后保留字符串,你必须更明确地使用你的代码,例如:
if foo != "" {
foo
} else if bar != "" {
bar
} else {
""
}