1. ホーム
  2. string

[解決済み] 関数の引数として、文字列(&String)、Vec(&Vec)、ボックス(&Box)への参照を受け取ることは、なぜ推奨されないのですか?

2022-05-07 01:50:36

質問

を受け取るRustコードを書きました。 &String を引数として与えます。

fn awesome_greeting(name: &String) {
    println!("Wow, you are awesome, {}!", name);
}

への参照を取り込むコードも書きました。 Vec または Box :

fn total_price(prices: &Vec<i32>) -> i32 {
    prices.iter().sum()
}

fn is_even(value: &Box<i32>) -> bool {
    **value % 2 == 0
}

しかし、このようなやり方は良くないという意見もいただきました。なぜダメなのでしょうか?

解決方法は?

TL;DR: 代わりに &str , &[T] または &T を使用することで、より汎用的なコードが可能になります。


  1. を使用する主な理由の1つは String または Vec または Vec .

  2. を受け付ける。 String , &String または &Vec また が必要です。 は、関数を呼び出す前にヒープ上に確保されていなければなりません。を受け入れると &Box は文字列リテラル(プログラムデータ内に保存)を許可し &str または &[T] は、スタックに確保された配列や変数を使用できます。不要なアロケーションはパフォーマンスの低下につながります。これは通常、これらのメソッドをテストの中で呼び出そうとすると、すぐにバレてしまいます。 &T メソッドを使用します。

    main
    
    awesome_greeting(&String::from("Anna"));
    
    
    total_price(&vec![42, 13, 1337])
    
    
  3. もう一つのパフォーマンスに関する考慮点は is_even(&Box::new(42)) , &String&Vec を参照する必要があるため、不必要なインダイレクトのレイヤーを導入してしまいます。 &Box を取得するために &String で、2回目のデリファレンスを行って、最終的に String .

代わりに 文字列スライス ( &str ), a スライス ( &str )、あるいは単なる参照( &[T] ). A &T , &String または &Vec<T> は自動的に強制されます (via デレフコークション ) を &Box<T> , &str または &[T] それぞれ

&T
fn awesome_greeting(name: &str) {
    println!("Wow, you are awesome, {}!", name);
}

fn total_price(prices: &[i32]) -> i32 {
    prices.iter().sum()
}

これで、これらのメソッドをより広い範囲の型を使って呼び出すことができるようになりました。例えば fn is_even(value: &i32) -> bool { *value % 2 == 0 } は、文字列リテラル ( awesome_greeting ) または 割り当てられた "Anna" . String は、配列への参照で呼び出すことができます ( total_price ) または 割り当てられた &[1, 2, 3] .


の項目を追加したり削除したりしたい場合は、以下のようにします。 Vec または String を取ることができます。 ミュータブルリファレンス ( Vec<T> または &mut String ):

&mut Vec<T>
fn add_greeting_target(greeting: &mut String) {
    greeting.push_str("world!");
}

スライスに特化した場合、スライスを受け取るために fn add_candy_prices(prices: &mut Vec<i32>) { prices.push(5); prices.push(25); } または &mut [T] . これにより、スライス内の特定の値を変異させることができますが、スライス内のアイテムの数を変更することはできません(つまり、文字列に対して非常に制限されます)。

&mut str
fn reset_first_price(prices: &mut [i32]) {
    prices[0] = 0;
}