2017-07-27 6 views
3

次のPythonコードは(この例では、barの内容)最初の非空の文字列を返します:私はルーストにそれを書くにはどうすればよい最初の空ではない文字列を返すにはどうすればよいですか?

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

?私は簡単に私は錆とPythonで何を行うことができないと仮定し

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` 

を取得しています:私はこれを試してみましたか?

+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

錆がtruthyの概念がありませんまたはfalsyの値はPythonのように、strをブール値として使用することはできません。実際、比較演算子を持つ実際のbool以外は使用できません。

matchを使用して@Aratz's solutionする代わりに、あなたが複数の文字列のために、この種類や機能が必要な場合は、マクロを使用することができます

let result = match (foo.is_empty(), bar.is_empty) { 
    (true,_) => Some(foo), 
    (_, true) => Some(bar), 
    _ => 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 
のように使用
macro_rules! first_nonempty { 
    ($($string:expr),+)=> ({ 
     $(
      if !$string.is_empty() { 
       Some($string) 
      } else 
     )+ 
     { 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"); 

あなたは2番目の引数が遅延評価されますが、以下の方法でOr形質を拡張できることを確認する必要がある場合:詳細はOption#orOption#or_else

fn or_else<F: FnOnce() -> Self>(self, f: F) -> Self; 

Optionの類似の方法を参照してください。

関連する問題