2017-07-27 72 views
3

以下Python代码返回的第一个非空字符串(在本例中,bar内容):如何返回第一个非空字符串?

foo = "" 
bar = "hello" 
foo or bar # returns "hello" 

我怎样写它的锈?我试着用这样的:

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做锈?

+2

python代码到底做了什么? –

+0

你为什么不直接连接字符串? – fancyPants

+0

@JanNilsFerner它返回第一个非空字符串(在本例中'bar'的内容) @fancyPants,因为有时'foo'可能已经被填充,并且我想在'foo'中返回内容而不是 – Jeffrey04

回答

1

这里的问题是Rust不会将逻辑表达式中的字符串(或其他)隐式转换为布尔值。

如果你想模仿Python的行为,即要保持字符串的布尔表达式之后,你必须更明确的与您的代码,如:

if foo != "" { 
    foo 
} else if bar != "" { 
    bar 
} else { 
    "" 
} 
+0

我做了'如果foo.is_empty(){bar} else {foo}'有效,但是我想知道是否有其他方法在介绍性材料中错过了(我是新手) – Jeffrey04

+1

不仅不会在这里进行隐式转换,Rust没有像Python那样的“真实性”概念,并且除了逻辑运算符使用的“bool”之外,它不允许*任何其他*。您无法覆盖这些运算符的行为。 –

4

锈没有概念truthyfalsy像Python一样的值,所以你不能使用str作为布尔值。事实上,除了实际的布尔与比较运算符,你不能使用任何东西。

使用match@Aratz's solution另一种方法是

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 
+0

如果OP错过了Python的工作方式,他可以把它放在像'str_or!(foo,bar)'这样的宏中。 – Boiethios

+0

大声笑,我可以看看如果我有3个或更多,那么我需要写的代码将更多 – Jeffrey04

+0

@ Jeffrey04如果你想我可以给你写一个宏,用于无限制的字符串。 –

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(&"") 
} 
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#orOption#or_else的更多细节。