2017-07-27 52 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的更多細節。

相關問題