2016-12-27 6 views
2

私は値への参照があり、ラッパーの値をラップする構造体への参照で置き換えたいと考えています。&Wrapperで置換&タイプ<Type>

例:

struct Wrapper<T>(T); 

let num = 123; 
let x: &i32 = &num; 
let wrapped: &Wrapper<i32> = .. // some conversion 

これは可能ですか? (安全な溶液が望ましいですが、必要ではありません)

答えて

2

C++から来る
let wrapped: &Wrapper<i32> = &Wrapper(*x); // type annotation optional 

我々はへの参照を取るので、あなたは、これは夢中になって安全ではないと思うかもしれません一時的なもの(左側の式)。しかし、このような状況では、Rustはこの一時的な式の結果をスタックに保存するだけです。上記のコードは、

let hidden = Wrapper(*x); 
let wrapped: &Wrapper = &hidden; 

と同等ですが、このリファレンスを返すときには問題が発生します。例:

fn wrap<T>(t: &T) -> &Wrapped<T> { 
    &Wrapped(*t) 
} 

ここでは2つの問題があります。最初に、tから移動することはできません(i32Copyなので、上記のコードでのみ動作しました)。次に、ローカル変数(hiddenは私たちのために作成されたもの)。


これを解決するには、unsafe機能std::mem::transmute()を使用することができます。これは、どんな型も他の型として解釈します。

お待ちください! unsafe {}は「コンパイラ、これを信頼してください!」という意味ですが、自分自身を信頼する必要がありますか?プログラマは、Wrapped<T>Tのデータレイアウトが全く同じであることを保証する必要があります。そうですか?

これはおそらくほとんどのプラットフォームで当てはまりますが、私たちがこれを保証できるかどうかは非常に疑問です!構造体(とユニット構造体)のデータレイアウトに関しては、Rustは多くのことを約束していないようです。フィールドを並べ替えることができ(この場合重要ではない)、パディングを追加することがあります。 repr(Rust) chapter of the Rustonomiconにこれに関する詳細があります。


を要約すると:wrap()のような機能がを安全に実装することができません。結果として、そのような機能を含むAPIは避けなければなりません。

+4

質問は、どのような条件の下で、「ラップ」関数がいつ発音するのですか?当社には、文書による保証はありません。 – bluss

+0

@bluss私はその問題に関するさらなる情報を追加しました。それは実際には危険であり、使用されるべきではないように思われるので、正確なコードも削除しました。私はSOの答えで '不安全な 'ソリューションを提供して申し訳ありません。私は通常それをしませんが、10分後にこのような答えを書いていました^ _^ –

+0

@bluss私はいくつかのアプリケーションでメモリレイアウトに関するいくつかの仮定をしていたと思います。'transmute((u32、u32)):: u64'は'(、) 'のレイアウトについて危険な仮定をします。このようなこと(レイアウト保証を強制する)が将来のRustでどのように解決されるのかを追跡する問題はありますか? –

1

あなたはコンバージョンを必要としません。あなたは、次のようにこれを達成することができます:あなたの例のコードを動作させるのは簡単だ

#[derive(Debug)] 
struct Wrapper(i32); 

let num = 123; // the value 
let x = &num; // the reference to the value 
let wrapped: Wrapper = Wrapper(*x); // now you can refer to &wrapped 

println!("{:?}", wrapped); 
関連する問題