編集:私はあなたが書いたことを気づいただけです "ボックス、コピーなどのタイプの回避策があると思いますが、私は主に慣用的な錆の解決策 "が、私はすでにすべての答えを入力しました。 :Pそして、以下の解答はです。イディオマティックな錆、これはまさに記憶の仕組みです!コンパイラがあなたを止めなくても、何か良いことが起こるわけではないので、CやC++でスタックに割り当てられたデータへのポインタを返そうとしないでください。 ;)
あなたが参照を返すいつでも、その参照は関数のパラメータとなっている必要があります。言い換えれば、データへの参照を返す場合、そのデータのすべてはの外に割り当てられていなければなりません。あなたはこれを理解しているようですが、私はそれがはっきりしていることを確認したいだけです。 :)
あなたのユースケースに応じて、この問題を解決する方法はたくさんあります。この特定の例では
、あなたは、あなただけですべての参照で悩まずにfoo
に所有権を与えることができ、その後何のためのx
を必要としないので:
fn foo(x: i64) -> Vec<i64> {
std::iter::repeat(x * 2).take(5).collect()
}
fn main() {
let x = 5;
println!("{:?}", foo(x));
}
をしかし、あなたはしたくないと言ってみましょう所有権をfoo
に渡す。あなたははまだ限り、あなたは根本的な価値変異させたくなかったので参照のベクトルを返すことができます:
fn foo(x: &i64) -> Vec<&i64> {
std::iter::repeat(x).take(5).collect()
}
fn main() {
let x = 5;
println!("{:?}", foo(&x));
}
を...と同様に、あなたは限り、あなたはしたくなかったとして根本的な価値を変異させることができ
fn foo(x: &mut i64) -> &mut i64 {
*x *= 2;
x
}
fn main() {
let mut x = 5;
println!("{:?}", foo(&mut x));
}
...しかし、両方ともしたいと思っています。したがって、メモリを割り当てて戻したい場合は、スタック以外の場所で行う必要があります。
// Just for illustration, see the next example for a better approach
fn foo(x: &i64) -> Vec<Box<i64>> {
std::iter::repeat(Box::new(x * 2)).take(5).collect()
}
fn main() {
let x = 5;
println!("{:?}", foo(&x));
}
...私はちょうどあなたがヒープを使用する一般的な手段としてBox
の認識しているようにしたい上記とかかわら:あなたができることの一つは、ちょうどBox
を使用して、ヒープ上でそれを詰めるです。正直、単にVec
を使用すると、あなたのデータはヒープに置かれることを意味し、これは動作します:
fn foo(x: &i64) -> Vec<i64> {
std::iter::repeat(x * 2).take(5).collect()
}
fn main() {
let x = 5;
println!("{:?}", foo(&x));
}
上記のように、これまでご利用の場合は、別の何かを要求するかもしれませんが、ここではおそらく最も慣用的な例です。
代わりに、Cの脚本とfoo
の外あらかじめ割り当てるメモリからトリックを引き出し、それを基準に渡すことができます。最後に
fn foo(x: &i64, v: &mut [i64; 5]) {
for i in v {
*i = x * 2;
}
}
fn main() {
let x = 5;
let mut v = [0; 5]; // fixed-size array on the stack
foo(&x, &mut v);
println!("{:?}", v);
}
、機能なければならない場合および参照データを変更する必要があります。および参照自体をコピーする必要があります。およびこれらのコピーされた参照を返す必要があります。0123このため:
use std::cell::Cell;
fn foo(x: &Cell<i64>) -> Vec<&Cell<i64>> {
x.set(x.get() * 2);
std::iter::repeat(x).take(5).collect()
}
fn main() {
let x = Cell::new(5);
println!("{:?}", foo(&x));
}
Cell
は(すべてのプリミティブ数値型が行う)Copy
形質を実装する型にCell
動作することに注意してくださいかかわらず、効率的かつ非意外でもあります。あなたのタイプがCopy
を実装していない場合は、RefCell
でこれと同じことをやりなおすことはできますが、ランタイムオーバーヘッドが軽くなり、 "借用"が間違っていると実行時にパニックが発生する可能性があります。
*しかし、私は同じ問題に遭遇すると思います* - これを試しましたか?なぜそれは同じ問題があると思いますか? – Shepmaster
@Shepmaster私はi64を新機能に割り当てたら、スタック上では、それは怒っていると思っていました。しかし、それは動作するようです。私はこれを推測しています。私は呼び出し元に所有権を戻しているので、貸し借りチェッカーは動揺しません。すなわち、借り入れはありませんか?そのような解決策は、BoxやCellのようなヒープ割り当て構造体を使用するよりも慣用的ですか? – William
借用に関係していないということは間違いありません。スタックに 'i64'を割り当て、' Vec'に所有権を移してから、 'Vec'の所有権を呼び出し元に転送します。 *ヒープ割り当て構造を含むものを使用するよりも慣用的です* - 'Vec' **は**"ヒープ割り当て構造を含む "です。この場合、 'Box'や' Cell'より 'Vec'を使う方が慣れ親しんでいると言います。この具体例では、配列 '[i64; 5] 'あなたが戻ってくる数字の数を知っているからです。 – Shepmaster