2017-08-02 7 views
2

私は危険な呼び出しの結果にsomevalを割り当て、後でsomevalを使用したい:安全でない呼び出しの結果にvarを割り当て、安全ではない{}の中に他のすべてを入れ子にすることなくそのvarを後で使用するというイディオムはありますか?

fn partially_unsafe(item: *const scary_c_struct) -> i32 { 
    let someval = item.as_ref(); 
    match someval { 
     Some(big_long_block) => { 
      //lots of lines of code 
      42 
     } 
     None => -1, 
    } 
} 

item.as_ref()ニーズがunsafeブロックであることをので、これはコンパイルされません:

fn partially_unsafe(item: *const scary_c_struct) -> i32 { 
    unsafe { 
     let someval = item.as_ref(); 
     match someval { 
      Some(big_long_block) => { 
       //lots of lines of code 
       42 
      } 
      None => -1, 
     } 
    } 
} 

この関数に他のネストされたブロックがたくさんあると面倒です。

私はこの表現を使用することができますが、これは不変性を覆す:

// ... 
let mut someval = None; 
unsafe { 
    someval = item.as_ref(); 
} 
// ... 

私はまた、独自の機能でitem.as_ref()を隠すことができます。

これらのどれも満足のいくものではありません。安全でない課題を表現するのが面倒な方法はありませんか?

+1

'partial_unsafe'関数は、' 'unsafe' 'unsafe fn partialy_unsafe ...'とマークすることをお勧めします。これは、Rust型システムと貸し出しチェッカーが確認できない契約を持っているからです。 '* const scary_c_struct'ポインタは有効です。そのような契約の存在を文書化することは、「安全でないfn」が存在する理由です。 – user4815162342

答えて

2

すぐに答えがされています。しかし、あなたが本当に欲しいものであることを繰延初期化

let someval; 
unsafe { 
    someval = item.as_ref(); 
} 
// use someval 

unsafeの醜い真実は、普及であり、unsafeブロックの境界をはるかに超えて浸出するということです。

は、例えば、上記可能:

let someval; // &T 
unsafe { 
    someval = &*(ptr::null() as *const T); 
} 

その場合、クラッシュは、おそらく、その原点がunsafeブロック内であっても、外部unsafeブロックをを発生します。

したがって、unsafeブロックを縮小することはここでは非生産的です。それはセキュリティの誤った感覚を誘発する。

+0

いずれにせよ、それはパニックになるでしょうか?安全でないブロックの内側と外側の間でクラッシュする違いがありますか? – marathon

+3

@marathonこれは制御された状況である*パニック*ではありません。これは、segfaultのような低レベルのメモリエラーです。そして、クラッシュは**良い**のケースです。また、秘密情報(パスワードなど)がデータを破損したり、任意のコードが実行されたりする可能性があります。 – Shepmaster

+1

逆に、 'unsafe'ブロックを縮小すると、エラーが直ちに発生する可能性が高くなりますどこか他の場所です。 'unsafe'ブロックの範囲を広げると、実際の安全でないもの(例えば、ヌルへのポインタを初期化する)を検索しなければならないコードの量が増え、論理エラーを検索するコードの量を減らすことはありませんエラーが発生しました。 – trentcl

3

ここで遅延評価は必要ありません。私はまた、

let mut a = 0; 
a += 1; 
let a = a; 

をことができます:あなたは、常に変数を再結合することにより可変性を放棄することができます

fn partially_unsafe(item: *const scary_c_struct) -> i32 { 
    let someval = unsafe { item.as_ref() }; 
    match someval { 
     Some(big_long_block) => { 
      //lots of lines of code 
      42 
     } 
     None => -1, 
    } 
} 

が、これは不変性

を覆す:ブロックと危険なブロックがあまりにも表現されています独自の機能でitem.as_ref()を非表示にします。関数がas_refと同じだろうとあなたは何を得ないだろうので、まだ、unsafeとしてマークされる必要があるであろうと愚かなことでしょう

。これは、反対のことを行うためにはるかより理にかなって - この機能のうち、安全な(または少なくとも安全な)コードを移動:

fn partially_unsafe(item: *const scary_c_struct) -> i32 { 
    unsafe { 
     item.as_ref().map_or(-1, |item| item.extracted_method()) 
    } 
} 

Matthieu M.'s answerは、スポットオン危険なの範囲についてですコンパイラの要件に加えて人間の目的にも役立ちます。ブロックの範囲を使用して安全でない場所に到達できる場所を強調すると便利です。

関連する問題