2016-12-20 6 views
2

間隔を表す自分の構造体にカスタムDisplay::fmtを実装しています。一致の式の寿命(!)が短すぎます

struct Range<T> { 
    lower: Option<T>, 
    upper: Option<T>, 
} 

範囲は、それが無限大(またはI仮定i32の限界)までの1からすべての整数を含む意味し、Range { lower: Some(1), upper: None }とすることができます。

私はバウンドがNoneではなく、それ以外の場合は、空の文字列を表示する場合TDisplay::fmtを使用するようにDisplay::fmtを実装する:

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!()によって生成された文字列の存続期間。私の実装での問題は、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

は偉大な答えをいただき、ありがとうございます。なぜ私の解決策がうまくいかなかったのか、私の問題に複数の解決策を提示していることから、私はShepmasterの答えを受け入れることにしました。 – runfalk

答えて

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!に電話するだけです。これは、少し重複を導入するかもしれませんが、おそらくより効率的です。フォーマッタがなければ、それは次のようになります。フォーマッタ内部print!(ため

fn main() { 
    let opt = Some(1); 

    print!("opt: "); 

    if let Some(ref x) = opt { 
     print!("{}", x); 
    } 

    println!("");  
} 

代替write!(f,をし、エラーに戻ります。

+0

'if let Some(ref x)='解決策は私が探しているものです。なぜ私の以前のコードがうまくいかなかったのか理解しています。錆で働くことは確かに目を開くことです。 thourough rundownに感謝します。 – runfalk

+0

複数の 'write!('は順番に何らかの結果を返すようですが、コンパイラは 'warning:未使用の結果を使用する必要があります... ' 'fmt :: Formatter'の' write! 'は失敗する可能性がありますか?これは悪い練習ですか? – runfalk

+0

@antennenはい、そして?Rustの他の場所と同様、' Result'を使用してくださいおそらく私が言及しているように、「誤りで戻ってくる」ことによって、おそらくは「誤り処理の章」(https://doc.rust-lang.org/stable/book/error-handling.html)の* Rust Programming Language *助けになるでしょうか?[あなたのために親切に実装を書いてくれたChris Emersonの答え](http://stackoverflow.com/a/41260867/155423) – Shepmaster

5

私は生涯について熟知していませんが、 format!で作成された&Stringを返信しようとしています。フォーマットの範囲はスコープ内のみであるため、貸し出しチェッカーは不平を言います。

これを修正するには、所有している文字列を使用します。

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); 
} 
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, ">") 
    } 
} 

Playground