トランスミュート
型システムから抜け出しましょう! 何がなんでもビットを再解釈します! この本は アンセーフなもの全てについて書かれていますが、この章でカバーされている操作を やるよりも、他の方法を見つけるよう深刻に考えるべきだということは、 いくら強調しようとも、強調しきれません。これは本当に、マジで、 Rust で出来る 最も恐ろしいアンセーフなことです。ここではガードレールは爪楊枝のように脆いです。
mem::transmute<T, U>
は型 T
の値を受け取り、その値が型 U
であると再解釈します。
唯一の制約は、 T
と U
が同じサイズを持つとされていることです。
この操作によって未定義動作が起こる方法を考えると、気が遠くなります。
- まず真っ先に、いかなる型においても、無効状態のインスタンスを作ることは、本当に予測不可能な混沌状態を引き起こすでしょう。
- transmute はオーバーロードされたリターン型を持ちます。もしリターン型を指定しなかった場合、 推論を満たす、びっくりするような型を生成するかもしれません。
- 無効なプリミティブを生成することは未定義動作を引き起こします。
- repr(C) でない型の間でのトランスミュートは未定義動作を引き起こします。
- & から &mut へのトランスミュートは未定義動作を引き起こします。
- & から &mut へのトランスミュートはいつも未定義動作を引き起こします。
- いいえ、これは出来ません。
- いいか、君は特別じゃないんだ。
- 明確にライフタイムが指定されていない参照へのトランスミュートは無制限のライフタイムを生成します。
mem::transmute_copy<T, U>
は、どうにかして transmute よりも本当に更にアンセーフな事をしようとします。
この関数は &T
から size_of<U>
バイトコピーし、これらを U
として解釈します。
もし U
が T
よりも大きい場合、未定義動作を引き起こしますが、 mem::transmute
の
サイズチェックはなくなっています ( T
の先頭部分をコピーすることが有効である場合があるためです) 。
そしてもちろん、これらの関数の機能のほとんどを、ポインタのキャストを利用することで 得ることができます。